导航属性应该是虚拟的-不需要在 ef 核心?

正如我在 EF 导航属性应该是虚拟的中所记得的:

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; }
}

但我看到的 EF Core并不是虚拟的:

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; }
}

现在不需要了吗?

70446 次浏览

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

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.

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;

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.

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.