Entity Framework object Framework formation journey -- Code First Framework Design (5), entity -- code
The previous several articles introduced the formation process of the Entity Framework. The overall Framework is mainly built based on the Database First method, that is, the EDMX file ing relationship, build the relationship between tables. This mode is flexible. You can also use a graphical designer to design the relationship between tables. This mode is usually used by many development projects, however, the problem is that the XML is too complex, so sometimes I want to use the Code First mode to build the entire framework. This article describes how to use Code First to build the entire framework and discuss the problems encountered.
1. SQL Server-based Code First Mode
To quickly understand the working mode of Code First, we should First develop and test the SQL Server database of Microsoft. We should First build a standard relational database according to the regular mode, as shown below.
This table contains several classic relationships. One is a Role table with a self-reference relationship, the other is a many-to-many relationship between the User and the Role table, and the other is a reference relationship between the User and UserDetail.
Generally, the relationship can meet the requirements of most projects. The database scripts for these tables are as follows.
create table dbo.Role ( ID nvarchar(50) not null, Name nvarchar(50) null, ParentID nvarchar(50) null, constraint PK_ROLE primary key (ID))gocreate table dbo."User" ( ID nvarchar(50) not null, Account nvarchar(50) null, Password nvarchar(50) null, constraint PK_USER primary key (ID))gocreate table dbo.UserDetail ( ID nvarchar(50) not null, User_ID nvarchar(50) null, Name nvarchar(50) null, Sex int null, Birthdate datetime null, Height decimal null, Note ntext null, constraint PK_USERDETAIL primary key (ID))gocreate table dbo.UserRole ( User_ID nvarchar(50) not null, Role_ID nvarchar(50) not null, constraint PK_USERROLE primary key (User_ID, Role_ID))goalter table dbo.Role add constraint FK_ROLE_REFERENCE_ROLE foreign key (ParentID) references dbo.Role (ID)goalter table dbo.UserDetail add constraint FK_USERDETA_REFERENCE_USER foreign key (User_ID) references dbo."User" (ID)goalter table dbo.UserRole add constraint FK_USERROLE_REFERENCE_ROLE foreign key (Role_ID) references dbo.Role (ID)goalter table dbo.UserRole add constraint FK_USERROLE_REFERENCE_USER foreign key (User_ID) references dbo."User" (ID)go
We use the Code Frist method we just introduced to construct the Entity Framework, as shown in the following steps.
1) Select the Code First method from the database.
2) Select the specified database connection and select the corresponding database table, as shown in the following figure (including the intermediate table UserRole ).
After a project is generated, several classes will be added to the project, including the Role entity class, User entity class, And UserDetail entity class (entity class without the intermediate table UserRole ), there is also a database context that contains these entity classes. The relationships between their tables are specified by code without the EDMX file.
The code for several class files is as follows. The entity class adds the description of [Table ("Role")] in the class definition header, indicates the relationship between the object class and the database table.
[Table("Role")] public partial class Role { public Role() { Children = new HashSet<Role>(); Users = new HashSet<User>(); } [StringLength(50)] public string ID { get; set; } [StringLength(50)] public string Name { get; set; } [StringLength(50)] public string ParentID { get; set; } public virtual ICollection<Role> Children { get; set; } public virtual Role Parent { get; set; } public virtual ICollection<User> Users { get; set; } }
Other classes are as follows.
[Table("User")] public partial class User { public User() { UserDetails = new HashSet<UserDetail>(); Roles = new HashSet<Role>(); } [StringLength(50)] public string ID { get; set; } [StringLength(50)] public string Account { get; set; } [StringLength(50)] public string Password { get; set; } public virtual ICollection<UserDetail> UserDetails { get; set; } public virtual ICollection<Role> Roles { get; set; } }
[Table("UserDetail")] public partial class UserDetail { [StringLength(50)] public string ID { get; set; } [StringLength(50)] public string User_ID { get; set; } [StringLength(50)] public string Name { get; set; } public int? Sex { get; set; } public DateTime? Birthdate { get; set; } public decimal? Height { get; set; } [Column(TypeName = "ntext")] public string Note { get; set; } public virtual User User { get; set; } }
Another class is the generated database context.
public partial class DbEntities : DbContext { public DbEntities() : base("name=Model1") { } public virtual DbSet<Role> Roles { get; set; } public virtual DbSet<User> Users { get; set; } public virtual DbSet<UserDetail> UserDetails { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Role>() .HasMany(e => e.Children) .WithOptional(e => e.Parent) .HasForeignKey(e => e.ParentID); modelBuilder.Entity<Role>() .HasMany(e => e.Users) .WithMany(e => e.Roles) .Map(m => m.ToTable("UserRole")); modelBuilder.Entity<User>() .HasMany(e => e.UserDetails) .WithOptional(e => e.User) .HasForeignKey(e => e.User_ID); modelBuilder.Entity<UserDetail>() .Property(e => e.Height) .HasPrecision(18, 0); } }
The operation class of the above database context specifies the relationship between several tables by using code in the OnModelCreating function, replacing the description of the EDMX file.
This seems to be much simpler than the EDMX file. I feel very happy and everything goes smoothly.
If we use this database context to insert a database, it will be executed smoothly and contain the relationship between multiple tables for processing. The Code is as follows.
Private void NormalTest () {DbEntities db = new DbEntities (); Role role = new Role () {ID = Guid. newGuid (). toString (), Name = "test33"}; User user = new User () {ID = Guid. newGuid (). toString (), Account = "test33", Password = "test33"}; UserDetail detail = new UserDetail () {ID = Guid. newGuid (). toString (), Name = "userName33", Sex = 1, Note = "Test content 33", Height = 175}; user. userDetails. add (detail); role. users. add (user); db. roles. add (role); db. saveChanges (); List <Role> list = db. roles. toList ();}
We found that through the operation of the code above, several tables have written data, and the reference relationships between them are included.
2. Extraction of Entity Framework based on generic warehousing Model
In order to better encapsulate different databases, I introduced the structure of the Entity Framework based on the generic storage mode introduced earlier. I hope it will be compatible with the support of multiple databases in the future, the layered structure of the final build code is as follows.
The layering of this framework is equivalent to providing unified and standard universal interfaces for various database accesses, providing a good guarantee for us to quickly implement various functions using various powerful base classes. The following code uses this layered framework.
Private void FrameworkTest () {Role role = new Role () {ID = Guid. newGuid (). toString (), Name = "test33"}; User user = new User () {ID = Guid. newGuid (). toString (), Account = "test33", Password = "test33"}; UserDetail detail = new UserDetail () {ID = Guid. newGuid (). toString (), Name = "userName33", Sex = 1, Note = "Test content 33", Height = 175}; user. userDetails. add (detail); role. users. add (user); ifacloud. instance <IRoleBLL> (). insert (role); ICollection <Role> list = ifacloud. instance <IRoleBLL> (). getAll ();}
We found that this part of code is executed in the same way as using the automatically generated database context DbEntities to operate the database. It can write data to each table and add relevant application relationships.
Full thinking that this can also easily expand to the Oracle database, but when using the entity class generated by the SQL Server database, when accessing the Oracle database, it is found that all the entity class names generated by it are in uppercase, once you modify the Camel formatting field, the corresponding table field cannot be found.
We have found many solutions and still cannot effectively avoid this problem because the names of tables or fields in Oracle are case sensitive. Let's take a look at the Oracle issue and solve it later, however, if you do not consider supporting multiple databases, it is really convenient to build the framework based on SQL Server database Code First. We do not need to maintain the troublesome EDMX file, you only need to dynamically Add the relationship between several tables in the code function.
The index of this series of articles is as follows:
Entity Framework formation journey -- Entity Framework based on generic warehousing model (1)
Entity Framework formation tour-using Unity object dependency injection to optimize Entity Framework (2)
The formation of Entity Framework object Framework -- Implementation of unified and asynchronous operations of basic interfaces (3)
Entity Framework formation journey-processing of Entity Data Model (EDM) (4)
Entity Framework object Framework formation journey -- Code First Framework Design (5)