103

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?

Community
  • 1
  • 1
Alexan
  • 8,165
  • 14
  • 74
  • 101

5 Answers5

136

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.

C Perkins
  • 3,733
  • 4
  • 23
  • 37
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • If it has no special meaning, why does the scaffold generate every navigational property with virtual? – Camilo Terevinto Jan 26 '17 at 19:24
  • 1
    @CamiloTerevinto Just in case? By default? It really doesn't matter now. – Ivan Stoev Jan 26 '17 at 19:25
  • Pretty interesting, in fact, i would like to know if they are default virtual for EF core, i don't think so – Antoine Pelletier Jan 26 '17 at 19:45
  • 3
    @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. – Ivan Stoev Jan 26 '17 at 19:51
  • if I declare as virtual anyway, it won't have any effect? – Alexan Jan 26 '17 at 21:17
  • 3
    Currently yes (no effect). It might in the future though. That's the whole point. – Ivan Stoev Jan 26 '17 at 21:22
  • 3
    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. – Johnny Oshika Dec 16 '17 at 18:58
  • Lazy Loading has been already introduced in EF Core 2.1. (30 May 2018) https://learn.microsoft.com/en-us/ef/core/querying/related-data – Mariusz Aug 14 '18 at 09:29
  • @Mariusz 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 :) – Ivan Stoev Aug 14 '18 at 10:14
  • 1
    @ 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. – Mariusz Aug 22 '18 at 14:55
  • @Mariusz 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. – Ivan Stoev Aug 22 '18 at 15:05
29

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;
Antoine Pelletier
  • 3,164
  • 3
  • 40
  • 62
  • 1
    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. – Renan Apr 19 '23 at 01:27
  • @Renan Yes, .Include function allow one to eagerly load something that is virtual ! – Antoine Pelletier Aug 04 '23 at 16:01
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.

Matt
  • 1,424
  • 1
  • 13
  • 17
  • 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. – Ivan Stoev Aug 14 '18 at 10:22
  • @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**. – beggarboy Jan 13 '20 at 17:49
  • @beggarboy It definitely is NOT required. `public ICollection SomeEntities { get; set; }` or `public SomeEntity SomeEntity { get; set; }` is enough for EF to detect navigation property, thus relationship. – Ivan Stoev Jan 13 '20 at 18:25
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

vasil oreshenski
  • 2,788
  • 1
  • 14
  • 21
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.

SvenAelterman
  • 1,532
  • 1
  • 15
  • 26