zoukankan      html  css  js  c++  java
  • EF6学习笔记四:一对多、多对多、一对一关系配置(Fluent API)

    要专业系统地学习EF前往《你必须掌握的Entity Framework 6.x与Core 2.0》这本书的作者(汪鹏,Jeffcky)的博客:https://www.cnblogs.com/CreateMyself/    

    现在就来到了重中之重的配置了:一对多、多对多、一对一关系的配置,我这里全部使用Fulent API 的方式来

    一对多

    一对多最简单了,写好你的数据模型,什么配置都不用做,生成的表结构就是你想要的

    来个简单基类

    public class BaseEntity
        {
            public BaseEntity() {
                this.Id = Guid.NewGuid().ToString();
                this.AddTime = DateTime.Now;
            }
    
            public string Id { get; set; }
            public DateTime AddTime { get; set; }
        }
    View Code

    来个简单图书馆类

    public class Library:BaseEntity
        {
            public string Name { get; set; }
            public virtual ICollection<Book> Books { get; set; }
        }
    View Code

    来个简单Book类

    public class Book:BaseEntity
        {
            public string Name { get; set; }
            public virtual  Library Library { get; set; }
        }
    View Code

    为他们公开DbSet属性

    public DbSet<Library> Librarys { get; set; }
            public DbSet<Book> Books { get; set; }
    View Code

    然后生成的表就是这样的

    在Book中有一个Library的外键,这是默认给生成的,你可能觉得这个外键名呢想以“FK_”开头,还有表名你也不满意,那行啊,来配置啊

    咱们现在的配置就来专业一点,我们把对每一个model的配置单独用一个类,最后通过反射的方式,把配置添加到上下文的OnModelCreating方法中

    你的OnModelCreating中只需要这样写,就行了,上一篇我弄错了

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
                var typeToRegister = Assembly.GetExecutingAssembly().GetTypes()
                    .Where(x => !string.IsNullOrEmpty(x.Namespace))
                    .Where(x => x.BaseType != null && x.BaseType.IsGenericType
                    && x.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
                foreach (var type in typeToRegister)
                {
                    dynamic configurationInstance = Activator.CreateInstance(type);
                    modelBuilder.Configurations.Add(configurationInstance);
                }
                base.OnModelCreating(modelBuilder);
            }
    View Code

    你的配置代码写在哪里呢?请看我的项目文件结构

    实体和配置分开放,便于管理,上下文里面你已经不用去管了

    来看具体的配置

    public class LibraryMap:EntityTypeConfiguration<Library>
        {
            public LibraryMap()
            {
                ToTable("tb_Librarys");   //   表名
                HasKey(x => x.Id);  //  主键
                Property(x => x.Name);
                HasMany(x => x.Books).WithRequired(x => x.Library).HasForeignKey(x => x.FK_Library_Id);
                //  从图书馆的角度配置,一个图书馆有多本书,一本书必须属于某一个图书馆,也可以从图书的角度去配置
            }
        }
    View Code
    public class BookMap:EntityTypeConfiguration<Book>
        {
            public BookMap()
            {
                ToTable("tb_Books");
                HasKey(x => x.Id);
                //  从图书的角度来配置是这样的
                //  HasRequired(x => x.Library).WithMany(x => x.Books).HasForeignKey(x => x.FK_Library_Id);
            }
        }
    View Code

    现在生成的表就是我们想要的了

    多对多

     多对多也简单,用学生和课程来举例,一个学生可以学习多门课程,一门课程也可以供多名学生来学习

    多对多的关系,在数据库中我们需要建立第三张表专门维护两者的关系。其中有两种方法,通过配置 ,自动创建第三张表;或者你显示的创建第三model

    public class Student500:BaseEntity
        {
            public string Name { get; set; }
            public virtual ICollection<Course500> Courses500 { get; set; }
        }
    View Code
    public class Course500:BaseEntity
        {
            public string Name { get; set; }
            public virtual ICollection<Student500> Students500 { get; set; }
        }
    View Code
    public class Stduent500Map:EntityTypeConfiguration<Student500>
        {
            public Stduent500Map()
            {
                ToTable("tb_Students500");
                HasKey(x => x.Id);
                HasMany(x => x.Courses500).WithMany(x => x.Students500)
                    .Map(x => x.ToTable("tb_StudentCourses500")
                    .MapLeftKey("Stduent500Id")
                    .MapRightKey("Course500Id"));
            }
        }
    View Code
    public class Course500Map:EntityTypeConfiguration<Course500>
        {
            public Course500Map()
            {
                ToTable("tb_Courses500");
                HasKey(x =>x.Id);
                Property(x => x.Name);
            }
        }
    View Code

    生成的表结构是这样的

     这应该是比较符合我们得期望了,我们来看一下显示地创建第三个model,怎么弄。上面生成的StudentCourses500,他没有自己的Id和AddTime,那么我们现在这样做就行了

    显示定义第三个表来维护student和course的关系

    public class Student100:BaseEntity
        {
            public string Name { get; set; }
            public byte Age { get; set; }
            public virtual ICollection<StudentCourse100> StudentCourse { get; set; }
        }
    View Code
    public class Course100:BaseEntity
        {
            public string Name { get; set; }
            public int ManimumStrength { get; set; }
            public virtual ICollection<StudentCourse100> StudentCourse { get; set; }
        }
    View Code
    public class StudentCourse100:BaseEntity
        {
            public string Student100Id { get; set; }
            public virtual Student100 Student100 { get; set; }
            public string Courses100Id { get; set; }
            public virtual Course100 Course100 { get; set; }
        }
    View Code
    public class Student100Map:EntityTypeConfiguration<Student100>
        {
            public Student100Map()
            {
                ToTable("tb_Student100");
    
                HasKey(x => x.Id);
    
                HasMany(x => x.StudentCourse)
                    .WithRequired(x => x.Student100)
                    .HasForeignKey(x => x.Student100Id);
            }
        }
    View Code
    public class Course100Map:EntityTypeConfiguration<Course100>
        {
            public Course100Map()
            {
                ToTable("tb_Course100");
                HasKey(x => x.Id);
    
                HasMany(x => x.StudentCourse)
                    .WithRequired(x => x.Course100)
                    .HasForeignKey(x => x.Courses100Id);
            }
        }
    View Code

    表结构如下

    显示定义第三张表,我们对这张表就有了更多的设置,只不过,添加数据时会有点绕

                    db.Students100.Add(new Student100
                    {
                        Name = "王五",
                        Age = 44,
                        StudentCourse = new List<StudentCourse100> {
                            new StudentCourse100{ Course100 = new Course100{ Name="生物",ManimumStrength=45} },
                            new StudentCourse100{ Course100 = new Course100{ Name="化学",ManimumStrength=45} },
                            new StudentCourse100{ Course100 = new Course100{ Name="历史",ManimumStrength=45} }
                        }
                    });
                    db.SaveChanges();
    View Code

    一对一 

    弄这个之前我来引用一段《你必须知道的.Net Framework 6.x 与 Core 2.0》作者的原话:“正常情况下,首先应该探讨一对一关系。但是如果使用过一对一关系,就会发现并不是那么简单,换句话说,一对一关系最为复杂,设计如何使用HasOptional 与 WithRequired 、WithOptionalPrincipal 、

    WithOptionalDependent”

    来用人和联系方式来举例配置一对一关系

    public class Person : BaseEntity
        {
            public string Name { get; set; }
            public virtual PersonContact PersonContact { get; set; }
        }
    View Code
    public class PersonContact : BaseEntity
        {
            public string Email { get; set; }
            public virtual Person Person { get; set; }
        }
    View Code
    public class PersonMap:EntityTypeConfiguration<Person>
        {
            public PersonMap() {
                ToTable("tb_Person");
                HasKey(x => x.Id);
                HasOptional(x => x.PersonContact)
                    .WithOptionalPrincipal(x => x.Person).Map(x => x.MapKey("FK_Person_Id"));
            }
        }
    View Code
    public class PersonContactMap:EntityTypeConfiguration<PersonContact>
        {
            public PersonContactMap()
            {
                ToTable("tb_PersonContact");
                HasKey(x => x.Id);
            }
        }
    View Code

    表结构如下

    上面我使用的是HasOptional、WithOptionalPrincipal来配置的,外键建立在PersonContact表上

    principal主要的,dependent从属的  那使用dependent 外键就会被建立在Person表上

    当然还有其他的配置,这一点我就不说了,免得乱了,各位可以自己去研究。

  • 相关阅读:
    logistics regression
    dir 以及 attrib
    python 爬取有道翻译
    spss 逐步回归
    JQuery传值给.ashx乱码
    字符串转换成json的三种方式
    启动数据库SQL Server Service Broker
    ASP.NET两种缓存方式
    VS安装控件后报错
    sql server中有不是全数字的字符串
  • 原文地址:https://www.cnblogs.com/jinshan-go/p/10260508.html
Copyright © 2011-2022 走看看