In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly introduces how Entity Framework uses Code First's entity inheritance mode, which is very detailed and has certain reference value. Friends who are interested must read it!
There are three entity inheritance modes in Entity Framework's Code First mode.
1. Table per Type (TPT) inheritance
2. Table per Class Hierarchy (TPH) inheritance
3. Table per Concrete Class (TPC) inheritance
I. TPT inheritance mode
TPT inheritance is useful when domain entity classes have inheritance relationships, and we want to persist these entity class models to the database so that each domain entity is mapped to a separate table. These tables are associated with each other using an one-to-one relationship, and the database maintains the relationship through a shared primary key.
Suppose there is a scenario where an organization maintains a database of all the people who work in a department, some of whom are employees with fixed wages, and some are temporary workers who are paid by the hour. To persist this scenario, we want to create three domain entities: Person, Employee, and Vendor classes. The Person class is the base class, and the other two classes inherit from the Person class. The entity class structure is as follows:
1. Using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace TPTPattern.Model {public class Person {public int Id {get; set;} public string Name {get; set;} public string Email {get; set;} public string PhoneNumber {get; set;}
Employee class structure
Using System;using System.Collections.Generic;using System.ComponentModel.DataAnnotations.Schema;using System.Linq;using System.Text;using System.Threading.Tasks;namespace TPTPattern.Model {[Table ("Employee")] public class Employee: Person {/ salary / public decimal Salary {get; set;}}
Vendor class structure
Using System;using System.Collections.Generic;using System.ComponentModel.DataAnnotations.Schema;using System.Linq;using System.Text;using System.Threading.Tasks;namespace TPTPattern.Model {[Table ("Vendor")] public class Vendor: Person {/ hourly salary / public decimal HourlyRate {get; set;}}
The class diagram in VS is as follows:
For the Person class, we use EF's default convention to map to the database, while for the Employee and Vendor classes, we use data annotations to map them to the table names we want.
Then we need to create our own database context class, which is defined as follows:
Using System;using System.Collections.Generic;using System.Data.Entity;using System.Linq;using System.Text;using System.Threading.Tasks;using TPTPattern.Model;namespace TPTPattern.EFDatabaseContext {public class EFDbContext: DbContext {public EFDbContext (): base ("name=Default") {} public DbSet Persons {get; set;}}
In the above context, we only added the DbSet of the entity class Person, not the DbSet of the other two entity classes. Because the other two domain models are derived from this model, we are equivalent to adding the other two classes to the DbSet collection, so that EF uses polymorphism to use the actual domain model. Of course, you can also use Fluent API and entity partner classes to configure mapping details.
2. Create a database using data migration
View the database table structure after creating the database using data migration:
In TPT inheritance, we want to create a separate table for each domain entity class that shares a primary key. Therefore, the generated database relationship diagram is as follows:
3. Fill in the data
Now let's use these domain entities to create an Employee and Vendor class to populate the data, defined as follows:
Using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using TPTPattern.EFDatabaseContext;using TPTPattern.Model Namespace TPTPattern {class Program {static void Main (string [] args) {using (var context = new EFDbContext ()) {Employee emp = new Employee () {Name= "Li Bai", Email= "LiBai@163.com", PhoneNumber= "18754145782" Salary=2345m} Vendor vendor = new Vendor () {Name= "du Fu", Email= "DuFu@qq.com", PhoneNumber= "18234568123", HourlyRate=456m}; context.Persons.Add (emp); context.Persons.Add (vendor) Context.SaveChanges ();} Console.WriteLine ("Information input succeeded");}
Query the populated data of the database:
We can see that each table contains separate data, and there is a shared primary key between these tables. So there is an one-to-one relationship between these tables.
Note: TPT mode is mainly used in one-to-one mode.
II. TPH mode
TPH inheritance is useful when domain entities have inheritance relationships, but we want to save data from all entity classes in a separate table. From the perspective of domain entities, the inheritance relationship of our model class is still the same as the screenshot above:
But from a database point of view, there should be only one table to hold the data. Therefore, the resulting database should look like this:
Note: from a database point of view, this schema is not elegant because we save extraneous data to a single table, which is not standard. If we use this method, there will always be redundant columns with null values.
1. Create an entity class with inheritance relationship
Now let's create an entity class to implement this inheritance. Note: the three entity classes created this time and those created before are only without the data annotations above, so that they will be mapped to a single table in the database (EF will default to use the DbSet attribute name or plural form of the parent class as the table name, and map the attributes of the derived class to that table). The class structure is as follows:
2. Create the data context using System;using System.Collections.Generic;using System.Data.Entity;using System.Linq;using System.Text;using System.Threading.Tasks;using TPHPattern.Model;namespace TPHPattern.EFDatabaseContext {public class EFDbContext: DbContext {public EFDbContext (): base ("name=Default") {} public DbSet Persons {get; set;} public DbSet Employees {get; set;} public DbSet Vendors {get; set Create a database using data migration
After using data migration to generate the database, you will find that there is only one table in the database, and the fields in the three entity classes are all in this table. The created database table is structured as follows:
Note: looking at the generated table structure, you will find that there is an additional Discriminator field in the generated table, which is used to find the actual type of record, that is, to find Employee or Vendor from the Person table.
4. Do not use the default generated to distinguish the types of multiple tables
Use Fluent API to modify the data context class. The definition of the modified class is as follows:
Using System;using System.Collections.Generic;using System.Data.Entity;using System.Linq;using System.Text;using System.Threading.Tasks;using TPHPattern.Model;namespace TPHPattern.EFDatabaseContext {public class EFDbContext: DbContext {public EFDbContext (): base ("name=Default") {} public DbSet Persons {get; set;} public DbSet Employees {get; set;} public DbSet Vendors {get; set } protected override void OnModelCreating (DbModelBuilder modelBuilder) {/ / force PersonType to be discriminator 1 on behalf of full-time staff 2 on behalf of temporary worker modelBuilder.Entity () .Map (m = > m.Requires ("PersonType"). HasValue (1). Map (m = > m.Requires ("PersonType"). HasValue (2)); base.OnModelCreating (modelBuilder) }}}
Re-use data migration to persist entities to the database and persist the database table structure after:
The generated PersonType column is of type int.
5. Populate data using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using TPHPattern.EFDatabaseContext;using TPHPattern.Model Namespace TPHPattern {class Program {static void Main (string [] args) {using (var context = new EFDbContext ()) {Employee emp = new Employee () {Name = "Li Bai", Email = "LiBai@163.com", PhoneNumber = "18754145782" Salary = 2345m} Vendor vendor = new Vendor () {Name = "du Fu", Email = "DuFu@qq.com", PhoneNumber = "18234568123", HourlyRate = 456m}; context.Persons.Add (emp) Context.Persons.Add (vendor); context.SaveChanges ();} Console.WriteLine ("Information input succeeded");} 6. Query data
Note: compared with the TPT schema, the TPH schema simply uses fewer table names for data annotations or Fluent API configuration subclasses. Therefore, if we do not provide an exact configuration between entities that have inheritance relationships, EF will treat it as TPH schema by default and put the data in a single table.
Third, TPC mode
The TPC inheritance schema is used when multiple domain entity classes are derived from a base class entity, and we want to save the data of all concrete classes in their respective tables, and when the abstract base class entity does not have a corresponding table in the database. The solid model is the same as before.
However, from a database point of view, there are only tables corresponding to all concrete classes, not tables corresponding to abstract classes. The generated database is shown below:
1. Create an entity class
Create a domain entity class, where the Person base class should be abstract and everything else is the same as above:
2. Configure the data context
The next step is to configure the database context. If we only add the DbSet generic property collection of Person to the database context, then EF will be treated as TPH inheritance. If we need to implement TPC inheritance, then we also need to use Fluent API to configure the mapping (of course, we can also use the configuration partner class). The database context class is defined as follows:
Using System;using System.Collections.Generic;using System.Data.Entity;using System.Linq;using System.Text;using System.Threading.Tasks;using TPCPattern.Model;namespace TPCPattern.EFDatabaseContext {public class EFDbContext: DbContext {public EFDbContext (): base ("name=Default") {} public virtual DbSet Persons {get; set } protected override void OnModelCreating (DbModelBuilder modelBuilder) {/ / MapInheritedProperties means inheriting all the above attributes modelBuilder.Entity () .Map (m = > {m.MapInheritedProperties (); m.ToTable ("Employees");}) ModelBuilder.Entity () .Map (m = > {m.MapInheritedProperties (); m.ToTable ("Vendors");}); base.OnModelCreating (modelBuilder);}
In the above code, the MapInheritedProperties method maps the inherited properties to the table, and then we map to different tables according to different object types.
3. Use data migration to generate database
The resulting database table is structured as follows:
If you look at the generated table structure, you will find that there is only a table corresponding to the concrete class in the generated database, but no table corresponding to the abstract base class. The table corresponding to the concrete entity class contains all the fields in the abstract base class.
4. Populate data using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using TPCPattern.EFDatabaseContext;using TPCPattern.Model Namespace TPCPattern {class Program {static void Main (string [] args) {using (var context = new EFDbContext ()) {Employee emp = new Employee () {Name = "Li Bai", Email = "LiBai@163.com", PhoneNumber = "18754145782" Salary = 2345m} Vendor vendor = new Vendor () {Name = "du Fu", Email = "DuFu@qq.com", PhoneNumber = "18234568123", HourlyRate = 456m}; context.Persons.Add (emp) Context.Persons.Add (vendor); context.SaveChanges ();} Console.WriteLine ("Information input succeeded");}
Query the database:
Note: although the data is inserted into the database, there is also an exception when running the program. The exception information is shown in the figure below. The reason for this exception is that EF tries to access the value in the abstract class, and it finds two records with the same Id, but the Id column is recognized as the primary key, so two records with the same primary key cause problems. This exception clearly indicates that stored or database-generated Id columns are not valid for TPC inheritance.
If we want to use TPC inheritance, we can either use GUID-based Id, or pass in Id from the application, or use some database mechanism that maintains the uniqueness of columns automatically generated for multiple tables.
This is all the content of the article "how Entity Framework uses Code First's entity inheritance mode". Thank you for reading! Hope to share the content to help you, more related knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.