zoukankan      html  css  js  c++  java
  • EF CodeFirst方式 Fluent Api配置

    一.One-to-One Relationship【一对一关系】

    两个表之间,只能由一个记录在另外一个表中。每一个主键的值,只能关联到另外一张表的一条或者零条记录。请记住,这个一对一的关系不是非常的普遍,并且大多数的一对一的关系,是商业逻辑使然,并且数据也不是自然地。缺乏这样一条规则,就是在这种关系下,你可以把两个表合并为一个表,而不打破正常化的规则。

    为了理解一对一关系,我们创建两个实体,一个是User另外一个是UserProfile,一个User只有单个Profile,User表将会有一个主键,并且这个字段将会是UserProfile表的主键和外键。我们看下图:

     

    创建两个实体,一个是User实体,另外一个是UserProfile实体。我们的User实体的代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF.Core.Data
    {
       public class User:BaseEntity
        {
           /// <summary>
           /// 用户名
           /// </summary>
           public string UserName { get; set; }
    
           /// <summary>
           /// 电子邮件
           /// </summary>
           public string Email { get; set; }
    
           /// <summary>
           /// 密码
           /// </summary>
           public string Password { get; set; }
    
           /// <summary>
           /// 导航属性--用户详情
           /// </summary>
           public virtual UserProfile UserProfile { get; set; }
        }
    }
    

      

    UserProfile实体的代码快如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace EF.Core.Data
    {
        /// <summary>
        /// 用户详情实体
        /// </summary>
       public class UserProfile:BaseEntity
        {
           /// <summary>
           /// 姓
           /// </summary>
           public string FirstName { get; set; }
    
           /// <summary>
           /// 名
           /// </summary>
           public string LastName { get; set; }
    
           /// <summary>
           /// 地址
           /// </summary>
           public string Address { get; set; }
    
           /// <summary>
           /// 导航属性--User
           /// </summary>
           public virtual User User { get; set; }
        }
    }
    

      

    就像你看到的一样,上面的两个部分的代码块中,每个实体都使用彼此的实体,作为导航属性,因此你可以从任何实体中访问另外的实体。

    使用Fluent Api配置Users实体:

    using EF.Core.Data;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity.ModelConfiguration;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF.Data.Mapping
    {
       public class UserMap:EntityTypeConfiguration<User>
        {
           public UserMap() 
           {
               //配置主键
               this.HasKey(s => s.ID);
    
               //给ID配置自动增长
               this.Property(s => s.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
               //配置字段
               this.Property(s => s.UserName).IsRequired().HasColumnType("nvarchar").HasMaxLength(25);
               this.Property(s => s.Email).IsRequired().HasColumnType("nvarchar").HasMaxLength(25);
               this.Property(s => s.AddedDate).IsRequired();
               this.Property(s => s.ModifiedDate).IsRequired();
               this.Property(s => s.IP);
    
               //配置表
               this.ToTable("User");
    
    
           }
        }
    }
    

      

    使用Fluent Api配置UserProfile实体

    using EF.Core.Data;
    using System;
    using System.Collections.Generic;
    using System.Data.Entity.ModelConfiguration;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF.Data.Mapping
    {
       public class UserProfileMap:EntityTypeConfiguration<UserProfile>
        {
           public UserProfileMap()
           {
               this.HasKey(s=>s.ID);
    
               this.Property(s => s.FirstName).IsRequired();
               this.Property(s => s.LastName).IsRequired();
               this.Property(s => s.Address).HasMaxLength(100).HasColumnType("nvarchar").IsRequired();
    
               this.Property(s => s.AddedDate).IsRequired();
               this.Property(s => s.ModifiedDate).IsRequired();
               this.Property(s => s.IP);
    
               //配置关系[一个用户只能有一个用户详情!!!]
               this.HasRequired(s => s.User).WithRequiredDependent(s => s.UserProfile);
    
               this.ToTable("UserProfile"); 
    
           }
        }
    }
    

      

    现在,我们创建一个数据库上下文类EFDbContext,这个类继承DbContext类,在这个数据库上下文类中,我们重写OnModelCreating方法,这个OnModelCreating方法,在数据库上下文(EFDbContext)已经初始化的完成的时候,被调用,在OnModelCreating方法中,我们使用了反射,来为每个实体生成配置类。

    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Data.Entity.ModelConfiguration;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF.Data
    {
        public class EFDbContext:DbContext
        {
            public EFDbContext()
                : base("name=DbConnectionString")
            { 
            }
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                {
                    var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
                   .Where(type => !String.IsNullOrEmpty(type.Namespace))
                   .Where(type => type.BaseType != null && type.BaseType.IsGenericType
                        && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
                    foreach (var type in typesToRegister)
                    {
                        dynamic configurationInstance = Activator.CreateInstance(type);
                        modelBuilder.Configurations.Add(configurationInstance);
                    }
                    base.OnModelCreating(modelBuilder);
                }  
               
            }
        }
    }
    

      

    二.One-to-Many Relationship【一对多关系】

    主键表的一个记录,关联到关联表中,存在,没有,或者有一个,或者多个记录。这是最重要的也是最常见的关系
    为了更好的理解一对多的关系,可以联想到电子商务系统中,单个用户可以下很多订单,所以我们定义了两个实体,一个是客户实体,另外一个是订单实体。我们看看下面的图片:

    实体Customers代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF.Core.Data
    {
      public  class Customer:BaseEntity
        {
          /// <summary>
          /// 客户名称
          /// </summary>
          public string Name { get; set; }
    
          /// <summary>
          /// 客户电子邮件
          /// </summary>
          public string Emial { get; set; }
    
          /// <summary>
          /// 导航属性--Order
          /// </summary>
          public virtual ICollection<Order> Orders { get; set; }
        }
    }
    

      

    实体Orders代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace EF.Core.Data
    {
       public class Order:BaseEntity
        {
           /// <summary>
           /// 数量
           /// </summary>
           public byte Quantity { get; set; }
    
           /// <summary>
           /// 价格
           /// </summary>
           public decimal Price { get; set; }
    
           /// <summary>
           /// 客户ID
           /// </summary>
           public int CustomerId { get; set; }
    
           /// <summary>
           /// 导航属性--Customer
           /// </summary>
           public virtual Customer Customer { get; set; }
        }
    }
    

      

    你已经在上面的代码中注意到了导航属性,Customer实体有一个集合类型的Order属性,Order实体有一个Customer实体的导航属性,也就是说,一个客户可以有很多订单。
    使用Fluent Api配置Customer实体
    using EF.Core.Data;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity.ModelConfiguration;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF.Data.Mapping
    {
       public class CustomerMap:EntityTypeConfiguration<Customer>
        {
           public CustomerMap()
           {
               this.HasKey(s => s.ID);
               //properties  
               Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
               Property(t => t.Name);
               Property(t => t.Email).IsRequired();
               Property(t => t.AddedDate).IsRequired();
               Property(t => t.ModifiedDate).IsRequired();
               Property(t => t.IP);
    
               //table  
               ToTable("Customers");  
           }
        }
    }
    

      

    使用Fluent Api配置Orders实体
    using EF.Core.Data;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity.ModelConfiguration;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF.Data.Mapping
    {
       public class OrderMap:EntityTypeConfiguration<Order>
        {
           public OrderMap()
           {
               this.HasKey(s=>s.ID);
               //fields  
               Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
               Property(t => t.Quanatity).IsRequired().HasColumnType("tinyint");
               Property(t => t.Price).IsRequired();
               Property(t => t.CustomerId).IsRequired();
               Property(t => t.AddedDate).IsRequired();
               Property(t => t.ModifiedDate).IsRequired();
               Property(t => t.IP);
    
               //配置关系【一个用户有多个订单,外键是CusyomerId】
               this.HasRequired(s => s.Customer).WithMany(s => s.Orders).HasForeignKey(s => s.CustomerId).WillCascadeOnDelete(true);
    
               //table  
               ToTable("Orders");  
           }
        }
    }
    

      

    上面的代码表示:用户在每个Order中是必须的,并且用户可以下多个订单,两个表之间通过外键CustomerId联系,我们使用了四个方法来定义实体之间的关系,Withmany方法允许多个。HasForeignKey方法表示哪个属性是Order表的外键,WillCascadeOnDelete方法用来配置是否级联删除。

    三.Many-to-Many Relationship【多对多关系】

    每条记录在两个表中,都可以关联到另外一个表中的很多记录【或者0条记录】。多对多关系,需要第三方的表,也就是关联表或者链接表,因为关系型数据库不能直接适应这种关系。

    为了更好的理解多对多关系,我们想到,有一个选课系统,一个学生可以选秀很多课程,一个课程能够被很多学生选修,所以我们定义两个实体,一个是Syudent实体,另外一个是Course实体。我们来通过图表看看,多对多关系吧:

    Student实体

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF.Core.Data
    {
       public class Student:BaseEntity
        {
            public string Name { get; set; }
            public byte Age { get; set; }
            public bool IsCurrent { get; set; }
            public virtual ICollection<Course> Courses { get; set; }  
        }
    }
    

      

    Courses实体

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace EF.Core.Data
    {
       public class Course:BaseEntity
        {
            public string Name { get; set; }
            public Int64 MaximumStrength { get; set; }
            public virtual ICollection<Student> Students { get; set; }  
        }
    }
    

      

    使用Fluent Api配置Student实体

    using EF.Core.Data;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity.ModelConfiguration;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF.Data.Mapping
    {
       public class StudentMap:EntityTypeConfiguration<Student>
        {
           public StudentMap()
           {
               //key  
               HasKey(t => t.ID);
    
               //property  
               Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
               Property(t => t.Name);
               Property(t => t.Age);
               Property(t => t.IsCurrent);
               Property(t => t.AddedDate).IsRequired();
               Property(t => t.ModifiedDate).IsRequired();
               Property(t => t.IP);
    
               //table  
               ToTable("Students");  
    
               //配置关系[多个课程,可以被多个学生选修]
               //多对多关系实现要领:hasmany,hasmany,然后映射生成第三个表,最后映射leftkey,rightkey
               this.HasMany(s => s.Courses).
                   WithMany(s => s.Students)
                   .Map(s => s.ToTable("StudentCourse").
                       MapLeftKey("StudentId").
                       MapRightKey("CourseId"));
           }
        }
    }
    

      

    上面的代码中,表示,一个学生可以选修多个课程,并且每个课程可以有很多学生,你知道,实现多对多的关系,我们需要第三个表,所以我们映射了第三个表,mapLeftkey和maprightkey定义了第三个表中的键,如果我们不指定的话,就会按照约定生成类名_Id的键。

    使用Fluent Api配置Courses实体

    using EF.Core.Data;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity.ModelConfiguration;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EF.Data.Mapping
    {
       public class CourseMap:EntityTypeConfiguration<Course>
        {
           public CourseMap()
           {
               this.HasKey(t => t.ID);//少了一行代码
               //property  
               Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
               Property(t => t.Name);
               Property(t => t.MaximumStrength);
               Property(t => t.AddedDate).IsRequired();
               Property(t => t.ModifiedDate).IsRequired();
               Property(t => t.IP);
    
               //table  
               ToTable("Courses");           
           }
        }
    }
    

      

    出处:https://www.cnblogs.com/caofangsheng/p/5715876.html

  • 相关阅读:
    【洛谷】P2880 [USACO07JAN]平衡的阵容Balanced Lineup(st表)
    【洛谷】P1052 过河(状压dp)
    【洛谷】P1541 乌龟棋(四维背包dp)
    【BZOJ】4721: [Noip2016]蚯蚓 / 【洛谷】P2827 蚯蚓(单调队列)
    【洛谷】P1064 金明的预算方案(dp)
    【洛谷】P3908 异或之和(异或)
    【洛谷】P2434 [SDOI2005]区间(暴力)
    【洛谷】P2694 接金币(排序)
    【BZOJ】1012: [JSOI2008]最大数maxnumber /【洛谷】1198(线段树)
    【游记】noip2017酱油记
  • 原文地址:https://www.cnblogs.com/chenzhaoyu/p/8830090.html
Copyright © 2011-2022 走看看