Note. It took me too much time to write this answer, just to refuse it when the other two appeared ...
The virtual keyword works along with two DbContext.Configuration properties:
ProxyCreationEnabled - Allows EF to break a dynamic proxy when an object is created by EFLazyLoadingEnabled - allows a dynamic proxy to load related objects when the navigation property is used for the first time
Lazy loading is transparently implemented through a dynamic proxy. A dynamic proxy is a class derived from your object that is created and compiled by EF at runtime. It overrides your virtual navigation properties and implements a logical check if related objects are already loaded or not. If this does not cause the context to load (it issues a new request to the database). Lazy loading can only be performed in the context of the context to which the entity is attached - if you manage the context, you cannot use it.
The creation of a dynamic proxy is controlled by the first property mentioned. When an instance of an object is created as proxied, you cannot “delete” the proxy. In addition, if you create an entity without a proxy (for example, by calling the constructor yourself), you cannot add it later (but you can use DbSet<T>.Create instead of the constructor to get a proxied instance).
The second property can be changed in real time of your entity instances, so you can avoid unnecessary database queries when working with your objects by changing it to false (sometimes this is very useful).
Include is a download. A bright load loads the related objects along with the main object and runs as part of the query of the main object (it adds SQL queries to the query and builds large result sets).
The advantage of an active download is to get all the data in advance with one call to the database. Especially if you know that you will need all of them, this may be the way to go. The disadvantage of impatient loading is the very large result sets if you use too many inclusions, as well as some restrictions (you cannot add ordering or filtering for loaded objects - it always loads all related objects).
The benefits of lazy loading are that you only download data when you really need it. This is useful if you do not know in advance if you really need to. The drawbacks are additional requests generated by EF in some scenarios when you do not expect them (any first access to this property will lead to lazy loading - even Count in the navigation collection will load all the data that can count into your application instead of asking for a counter from databases - this is called extra lazy loading , and it is not yet supported by EF). Another big problem is the N + 1 problem. If you upload several brands and you get access to the manufacturer’s property, going through all the downloaded brands, without using intensive loading, you will generate N + 1 database queries (where N is the number of brands ) - one for downloading all brands and one for the manufacturer of each brand.
There is another option called explicit loading. This seems like lazy loading, but for you it is not transparent. You must execute it yourself using the context class:
context.Entry(brand).Reference(b => b.Manufacturer).Load();
In this case, this is not very useful, but it would be useful if you have the Brands navigation property in the Manufacturer class, because you can do this:
var dataQuery = context.Entry(manufacturer).Collection(m => m.Brands).Query();
Now you have an instance of IQueryable<Brand> , and you can add any condition, arrange, or even add an extra load and execute it against the database.