Code First Entity Framework 6 passive to active explicit it loading mode practical analysis (with source Code), entityloading
There are three ways to use Entity Framework to load correlated entities:
1. lazy Loading );
2. Greedy loading (eager loading );
3. explicit loading ).
EF uses lazy Loading by default ). Everything is automatically handled by EF.
This method may cause applications to connect to the Database Multiple times. In this case, we recommend that you use it when the data volume is large. When we need to load less data, loading all data at a time is more efficient.
Let's take a look at how EF's explicit loading gives us full control over data loading (not automated ).
Here we use the Code First mode.
Data Table: Product table, product category table, and brand table
Step 1: Create a console application and add an EF6 reference (you can use NuGet to obtain it)
Step 2: create three object objects: Product, Category, and Brand
Product entity class:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace EFExplicitLoading.Models { 7 public class Product { 8 public int ProductId { get; set; } 9 public String Title { get; set; }10 public int CategoryId { get; set; }11 12 public virtual Category Category { get; set; }13 14 public virtual Brand Brand { get; set; }15 16 }17 }
Category entity class:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace EFExplicitLoading.Models { 7 public class Category { 8 9 public Category() {10 Products = new HashSet<Product>();11 }12 13 public int CategoryId { get; set; }14 public String Name { get; set; }15 16 public virtual ICollection<Product> Products { get; set; } 17 }18 }
Brand entity class:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace EFExplicitLoading.Models { 7 public class Brand { 8 9 public Brand() {10 Products = new HashSet<Product>();11 }12 13 public int BrandId { get; set; }14 15 public String Name { get; set; }16 17 public virtual ICollection<Product> Products { get; set; } 18 }19 }
Step 3: Create a class (ExplicitContext) derived from DbContext)
1 using System.Data.Entity; 2 using EFExplicitLoading.Models; 3 4 namespace EFExplicitLoading { 5 6 public class ExplicitContext : DbContext { 7 public ExplicitContext() 8 : base("ExplicitConnectionString") { 9 }10 11 public DbSet<Product> Products { get; set; }12 13 public DbSet<Category> Categories { get; set; }14 15 public DbSet<Brand> Brands { get; set; }16 17 protected override void OnModelCreating(DbModelBuilder modelBuilder) {18 modelBuilder.Entity<Product>().ToTable("Product");19 modelBuilder.Entity<Brand>().ToTable("Brand");20 modelBuilder.Entity<Category>().ToTable("Category");21 }22 }23 24 }
Step 4: add the connectionStrings node in App. config
1 <connectionStrings>2 <add name="ExplicitConnectionString" connectionString="Data Source=.;Initial Catalog=EFExplicit;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />3 </connectionStrings>
Preparation is ready. When we use the ExplicitContext class, EF will automatically create databases and tables based on the entity.
Return to the console entry function:
Step 5: add Test Data
1 2 using (var context = new ExplicitContext () {3 // clear data 4 context first. database. executeSqlCommand ("delete from product"); 5 context. database. executeSqlCommand ("delete from brand"); 6 context. database. executeSqlCommand ("delete from category"); 7 8 var category1 = new Category {Name = "apparel"}; 9 var category2 = new Category {Name = ""}; 10 var brand1 = new Brand {Name = "Brand 1"}; 11 var brand2 = new Brand {Name = "Brand 2"}; 12 13 context. products. add (new Product {Brand = brand1, Category = category1, Title = "Product 1"}); 14 context. products. add (new Product {Brand = brand1, Category = category2, Title = "Product 2"}); 15 context. products. add (new Product {Brand = brand1, Category = category2, Title = "Product 3"}); 16 context. products. add (new Product {Brand = brand2, Category = category2, Title = "Product 4"}); 17 context. products. add (new Product {Brand = brand2, Category = category2, Title = "Product 5"}); 18 context. products. add (new Product {Brand = brand2, Category = category2, Title = "Product 6"}); 19 context. saveChanges (); 20}
Step 6: start testing explicit loading
1 using (var context = new ExplicitContext () {2 // disable lazy loading 3 context. configuration. lazyLoadingEnabled = false; 4 5 var category = context. categories. first (c => c. name = ""); 6 7 // determine whether the products associated with the category have been loaded 8 if (! Context. entry (category ). collection (x => x. products ). isLoaded) {9 context. entry (category ). collection (x => x. products ). load (); 10 Console. writeLine ("category {0} products are displayed and loaded... ", category. name); 11} 12 13 Console. write ("A total of {1} products under category {0}", category. name, category. products. count (); 14 15 foreach (var product in context. products) {16 if (! Context. entry (product ). reference (x => x. category ). isLoaded) {17 context. entry (product ). reference (x => x. category ). load (); 18 Console. writeLine ("category {0} is displayed and loaded. ", product. category. name); 19} 20 else {21 Console. writeLine ("category {0} has been loaded. ", product. category. name); 22} 23} 24 25 // use category again to calculate the number of products 26 Console. writeLine ("{1} products under {0} categories after the product is loaded", category. name, category. products. count (); 27 28 category. products. clear (); 29 Console. writeLine ("the product set is cleared. "); 30 Console. writeLine ("{1} products under the {0} category", category. name, category. products. count (); 31 32 33 context. entry (category ). collection (x => x. products ). load (); 34 Console. writeLine ("re-display the loaded product"); 35 Console. writeLine ("{1} products under the {0} category", category. name, category. products. count (); 36 37 // use ObjectContext to refresh the object 38 var objectContext = (IObjectContextAdapter) context ). objectContext; 39 var objectSet = objectContext. createObjectSet <Product> (); 40 objectSet. mergeOption = MergeOption. overwriteChanges; 41 objectSet. load (); 42 // MergeOption. appendOnly43 // MergeOption. overwriteChanges44 // MergeOption. noTracking45 // MergeOption. preserveChanges46 48 Console. writeLine ("Product Set uses MergeOption. overwriteChanges method "); 49 Console. writeLine ("{1} products under the {0} category", category. name, category. products. count (); 50} 51 52 53 Console. writeLine ("test part loading... "); 54 // test part loading, then load all 55 using (var context = new ExplicitContext () {56 // disable lazy loading 57 context. configuration. lazyLoadingEnabled = false; 58 var category = context. categories. first (c => c. name = "Household Appliances"); 59 // load 1 piece of data first 60 Console. writeLine ("loading 1 piece of data first"); 61 context. entry (category ). collection (x => x. products ). query (). take (1 ). load (); 62 Console. writeLine ("A total of {1} products under category {0}", category. name, category. products. count (); 63 64 // load all 65 context. entry (category ). collection (x => x. products ). load (); 66 Console. writeLine ("load all data"); 67 68 Console. writeLine ("{1} products under the {0} category", category. name, category. products. count (); 69} 70 71 Console. readKey ();
Execution result:
Disable lazy loading)
To test our explict loading, you must first disable lazy loading. There are two ways to disable lazy loading:
1. Set Context. Configuration. LazyLoadingEnabled to false or
2. Remove the virtual access modifier of the correlated object attributes (navigation attributes) in each object class. This method can more accurately control the lazy loading, that is, only disable the lazy loading of the removed virtual modifier object.
IsLoaded attributes and Load methods
Next, we use EF to obtain a Category object data with the Name of household appliances. Because Category and Product are one-to-multiple relationships, in this case, we can use the IsLoaded attribute to test whether the Products set under this category is loaded.
Context. Entry (category). Collection (x => x. Products). IsLoaded
If not, we use the Load method to Load the associated Products. In the next foreach traversal, we can see that all the Products associated with Category have been loaded.
PS:When the Take (n) method is used to Load data, the IsLoaded attribute is still False, because IsLoaded is true only when all associated data is loaded.
Link repair (
Relationship fixup)
Here, Entity Framework uses a technology called "link Repair (Relationship fixup), That is, when we separately load the associated entities (Product), the data will be automatically mounted to the loaded entities (Category), but this relationship fix does not always take effect, for example, this is not the case in the Multi-to-many relationship.
About Clear ()
Then we print out how many Products are in the Category, and then use the Clear () method to Clear the associated set Products of the category object.
The Clear method removes the association between the Category and the Product, but the data in the Product set is not deleted and still exists in the context memory, but it is no longer associated with the Category.
Then we re-Load the Product using Load, but the value of category. Products. Count () is still 0. This exactly shows the nature of the Clear method.
This is because Load loads data using MergeOption. AppendOnly by default, and the Product instance cannot be found (Clear ). Then we re-associate the data using MergeOption. OverwriteChanges.
About MergeOption (entity merging option)
MergeOption enumeration has four options
1. MergeOption. AppendOnly
Merge based on existing relationships
2. MergeOption. OverwriteChanges
In OverwriteChanges mode, the value of the current context instance is updated from the database (instances that use the same object, such as category ).
This mode is useful when you want to restore the changes in the context of an object and refresh the object from the database.
3. MergeOption. NoTracking
The trackless mode does not track object changes or realize that the object has been loaded to the current context.
NoTracking can be applied to the navigation attribute of an object (associated with the object attribute), but this object must also use NoTracking.
When NoTracking is applied to an object, the default AppendOnly mode is ignored for the navigation attribute of this object and the NoTracking mode is used.
4. MergeOption. PreserveChanges
The PreserveChanges option is essentially opposite to the OverwriteChanges option,
In PreserveChanges mode, the query result set is updated (if the database changes), but the value in the current context memory is not updated.
PS: You may have noticed that here we use the ObjectContext object instead of the context object, because DbContext cannot directly use the MergeOption type, so we must use the ObjectContext object.
Performance Improvement
When the number of correlated object sets is limited at any time, using the Load method will help us improve program performance, such as loading five products in a Category.
In a few scenarios, we can also use the Load
PS: when an object is in the Added (ADD), Deleted (delete), Detected (detach) status, the Load method cannot be used.
There are still many ways to improve the performance of Entity Framework. Of course, we must optimize it based on the actual situation of our project. Select different optimization solutions for different application scenarios
Sample Code: Click here to download