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

C#Entity FrameworkVirtualEntity Framework-CoreNavigation Properties

C# Problem Overview


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?

C# Solutions


Solution 1 - C#

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.

Solution 2 - C#

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.

Solution 3 - C#

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;

Solution 4 - C#

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://docs.microsoft.com/en-us/ef/core/querying/related-data

Solution 5 - C#

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlexanView Question on Stackoverflow
Solution 1 - C#Ivan StoevView Answer on Stackoverflow
Solution 2 - C#MattView Answer on Stackoverflow
Solution 3 - C#Antoine PelletierView Answer on Stackoverflow
Solution 4 - C#vasil oreshenskiView Answer on Stackoverflow
Solution 5 - C#SvenAeltermanView Answer on Stackoverflow