navigation property should be virtual - not required in ef core?
Asked Answered
B

5

106

As I remember in EF navigation property should be virtual:

public class Blog 
{  
    public int BlogId { get; set; }  
    public string Name { get; set; }  
    public string Url { get; set; }  
    public string Tags { get; set; }  

    public virtual ICollection<Post> Posts { get; set; }  
}

But I look at EF Core and don't see it as virtual:

public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }

Is it not required anymore?

Babcock answered 26/1, 2017 at 19:14 Comment(0)
H
139

virtual was never required in EF. It was needed only if you want lazy loading support.

Since Lazy loading is not yet supported by EF Core, currently virtual have no special meaning. It would when (and if) they add lazy loading support (there is a plan for doing so).

Update: Starting with EF Core 2.1, Lazy loading is now supported. But if you don't add Microsoft.EntityFrameworkCore.Proxies package and enable it via UseLazyLoadingProxies, the original answer still applies.

However if you do so, the thing's totally changed due to the lack of the opt-in control in the initial implementation - it requires all your navigation properties to be virtual. Which makes no sense to me, you'd better not use that until it gets fixed. If you really need lazy loading, use the alternative Lazy loading without proxies approach, in which case again virtual doesn't matter.

Huda answered 26/1, 2017 at 19:22 Comment(11)
If it has no special meaning, why does the scaffold generate every navigational property with virtual?Hoppe
@CamiloTerevinto Just in case? By default? It really doesn't matter now.Huda
Pretty interesting, in fact, i would like to know if they are default virtual for EF core, i don't think soC
@AntoinePelletier I don't know either - I'm not using scaffolding at all. But knowing the current EF Core status - bugs, incomplete features, weird internal exceptions on simple valid queries, what does the tooling (in particular scaffolding) should be the less concern for people using it.Huda
if I declare as virtual anyway, it won't have any effect?Babcock
Currently yes (no effect). It might in the future though. That's the whole point.Huda
With Scaffold-DbContext in EF Core 1.X, all navigational properties were virtual. I just re-scaffolded after upgrading to EF Core 2.X and all navigational properties are no longer virtual.Pneumoconiosis
Lazy Loading has been already introduced in EF Core 2.1. (30 May 2018) learn.microsoft.com/en-us/ef/core/querying/related-dataDemoss
@Demoss Still it doesn't affect you if you don't install and enable explicitly the lazy loading proxies. And if you do so, then you can simply follow the EF Core documentation. The question and main point in the answer is whether virtual is required or not. So I stay on the point that it's not required, except you explicitly decide to make it required by using incomplete feature :)Huda
@ Ivan Stoev I noticed "Since Lazy loading is not yet supported by EF Core" in the answer, so mentioned that it already is which caused update to the answer. That was my intention.Demoss
@Demoss I know, and really appreciate your comment! Sorry if it was unclear from my comment to it - my intent was just to justify the main point in the answer.Huda
C
30

Virtual key word has never been REQUIRED... It's optional.

What does it change ?

1. if you declare your property virtual :

Your virtual property (by default) won't be loaded right away when querying the main object. It will be retreive from the database ONLY if you try to access it, or access one of it's components.

And this is called lazy loading.

2. if you declare it non-virtual :

Your property will (by default) be loaded right away along with all the other property in your main entity. This means your property will be ready to access : it has already been retreived. Entity won't have to query again the database because you access this property.

This is called eagerly loading.

My opinion :

More often i choose eagerly loading (non-virtual) because most of the time, i need every property of every entity to be used along without having to query back (faster in the case you really want everything quick) but if you access this property only once in a while (your not listing anything) and you want more often just the rest of the informations exept THIS one, then make it virtual so this property won't slow down the rest of the query just for a few access.

Hope this was clear...

Exemples :

Where i would NOT use virtual (Eagerly) :

foreach(var line in query)
{
    var v = line.NotVirtual; // I access the property for every line
}

Where i would use virtual or lazy loading :

foreach(var line in query)
{
   if(line.ID == 509)        // because of this condition
   var v = line.Virtual; // I access the property only once in a while
}

one last thing :

If you don't query over 1 000 lines of a database, then whatever you choose won't have a big effect. Also, you can declare these property virtual and if you want to test the other way around, you just have to do this (Entity 4.0) :

context.LazyLoadingEnabled = false;

It will cancel the virtual effect.

Edit

For newer versions of EF :

WhateverEntities db = new WhateverEntities() 
db.Configuration.LazyLoadingEnabled = false;
C answered 26/1, 2017 at 19:27 Comment(2)
Best Answer so far! But I would like to add one thing, I always recommend using Virtual and if you need to access the data together with the parent entity, just use the .Include property in your searches in the database.Fireproof
@Fireproof Yes, .Include function allow one to eagerly load something that is virtual !C
S
26

Things have changed since the accepted answer was written. In 2018, Lazy Loading is now supported as of Entity Framework Core 2.1 for two different approaches.

The simpler way of the two is using proxies, and this will require the properties desired to be lazily loaded to be defined with virtual. To quote from the linked page:

The simplest way to use lazy-loading is by installing the Microsoft.EntityFrameworkCore.Proxies package and enabling it with a call to UseLazyLoadingProxies. [...] EF Core will then enable lazy-loading for any navigation property that can be overridden--that is, it must be virtual and on a class that can be inherited from.

And here is the provided sample code:

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Post> Posts { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public virtual Blog Blog { get; set; }
}

There is another way of doing Lazy Loading without proxies, which is to inject ILazyLoader into the constructor of the data type. This is explained in here.

In short, there are two ways to perform Lazy Loading: with and without proxies. virtual is required if and only if you wish to support Lazy Loading with proxies. Otherwise, it is not.

Synchronize answered 2/4, 2018 at 18:49 Comment(3)
Things have changed, but the point in my answer is still valid - navigation properties are still not required except you put yourself in a situation where they are required due to released incomplete feature. When the lazy loading with proxies is fixed, your answer will be invalidated, and again virtual will not be required as it should.Huda
@IvanStoev Then how come I searched for exactly this, because EF6 would try to insert and "link" entities in a child-collection, where-as the virtual keyword instantly made EF6 understand that the entities in the collection can be stand-alone and hence only included the references to them, therefore creating FKs as wanted. I have a slight fear that you misunderstood the importance of the keyword. Not only does virtual enable lazy-loading, it also solved the very problem I had above in a slightly more complex application. I am not buying it that it straightforward is not required.Unless
@Unless It definitely is NOT required. public ICollection<SomeEntity> SomeEntities { get; set; } or public SomeEntity SomeEntity { get; set; } is enough for EF to detect navigation property, thus relationship.Huda
K
4

In EF Core has choosen the path of discouraging lazy loading by default. Also i think this feature is still not implemented following this issue.

https://github.com/aspnet/EntityFramework/issues/3312

With the previous versions of EF the virtual navigation properties allowed to lazy load the related entities.

I guess loading navigation properties for now can be achived only with .Include(...)

EDIT:

There are several ways of loading related entities which are supported in Core. If you are interested: https://learn.microsoft.com/en-us/ef/core/querying/related-data

Kuntz answered 26/1, 2017 at 19:20 Comment(0)
K
1

Update: an initial implementation of lazy loading, planned for EF Core 2.1, will require navigation properties to be declared virtual. See https://github.com/aspnet/EntityFrameworkCore/issues/10787, and more generally to track progress on lazy loading, see https://github.com/aspnet/EntityFrameworkCore/issues/10509.

Kirtle answered 5/2, 2018 at 22:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.