virtual keyword, Include extension method, lazy loading, eager loading - how does loading related objects actually work

前端 未结 3 1096
失恋的感觉
失恋的感觉 2021-01-02 22:12

Loading related object in MVC can be pretty confusing.

There are lots of terms you need to be aware of and learn if you really want to know what you\'re doing when w

3条回答
  •  悲哀的现实
    2021-01-02 22:30

    Note: It took me too long to write this answer to just discard it when two other appeared ...

    Virtual keyword works together with two properties DbContext.Configuration:

    • ProxyCreationEnabled - allows EF crating dynamic proxy when the object is created by the EF
    • LazyLoadingEnabled - allows dynamic proxy to load related entities when the navigation property is used for the first time

    Lazy loading is transparently implemented through dynamic proxy. Dynamic proxy is class derived from your entity which is created and compiled by EF at runtime. It overrides your virtual navigation properties and implements logic checking if related entities were already loaded or not. If not it triggers a loading on the context (issues a new query to the database). Lazy loading can be executed only in the scope of the context to which the entity is attached - if you dispose the context you cannot use it.

    Dynamic proxy creation is controlled by the first mentioned property. Once the entity instance is created as proxied you cannot "remove" the proxy. Also if you create entity without proxy (for example by calling constructor yourselves) you cannot add it later (but you can use DbSet.Create instead of constructor to get the proxied instance).

    The second property can be changed during live time of your entity instances so you can avoid unnecessary queries to the database when working with your entities by changing it to false (it is sometimes very useful).

    Include represents eager loading. Eager loading loads related entities together with the main entity and it is executed as part of the main entity's query (it adds SQL joins to the query and builds a big result sets).

    Benefit of eager loading is to get all data upfront with one roundtrip to the database. Especially if you know that you will need all of them it can be a way to go. Disadvantage of eager loading are very big result sets if you use too many includes as well as some limitations (you cannot add ordering or filtering to loaded entities - it always loads all related objects).

    Benefit of lazy loading is to load data only when you really need them. It is helpful if you don't know upfront if you will really need them. Disadvantages are additional queries generated by EF in some scenarios when you don't expect them (any first access to the property will trigger the lazy loading - even Count on navigation collection will trigger loading of all data to be able to do count in your application instead of querying count from the database - this is called extra lazy loading and it is not natively supported by EF yet). Another big issue is N+1 problem. If you load several brands and you will access their manufacturer property by looping through all loaded brands without using eager loading, you will generate N+1 queries to database (where N is number of brands) - one for loading all brands and one for a manufacturer of each brand.

    There is another option called explicit loading. It is like lazy loading but it is not transparently executed for you. You must execute it yourselves by using context class:

    context.Entry(brand).Reference(b => b.Manufacturer).Load();
    

    It is not very useful in this case but it would be useful if you have Brands navigation property on the Manufacturer class because you can do this:

    var dataQuery = context.Entry(manufacturer).Collection(m => m.Brands).Query();
    

    Now you have a IQueryable instance and you can add any condition, ordering or even additional eager loading and execute it against the database.

提交回复
热议问题