• EntityFramework Code-First 简易教程(九)-------一对多


    一对多(One-to-Many)关系:

    下面,我们来介绍Code-First的一对多关系,比如,在一个Standard(年级)类中包含多个Student类。

    如果想了解更多关于one-to-one,one-to-many,many-to-many关系的信息,请访问Entity Relationship

    1.使用DataAnnotations配置One-to-Many关系:

    如下代码所示:

    public class Student
    {
        public Student() { }
    
        public int StudentId { get; set; }
        public string StudentName { get; set; }
    
        public virtual Standard Standard { get; set; }
    }
           
    public class Standard
    {
        public Standard()
        {
            Students = new List<Student>();
        }
        public int StandardId { get; set; }
        public string Description { get; set; }
    
        public virtual ICollection<Student> Students { get; set; }
    }

    如上代码所示,Student实体类包含导航属性Standard,而且Standard实体类包含集合属性Student,这就是默认的一对多关系。

    如果实体类遵循这种这种默认约定,也就是默认即是一对多关系了,我们就不需药额外的配置DataAnnotations或者Fluent API。

    在数据库中,Code-First会通过在Student表中加入Standard_StandardId外键列来创建一对多关系。

    one-to-one relationship in code first

    我们建议在一个实体类中包含外键属性,如上代码中,如果在Student实体类中创建StandardId属性,它就会自动变成外键,因为它遵循了默认约定,即外键的格式应该为<类型名称>Id的格式。

    同样的,如果我们创建的外键属性名字没有遵循默认的命名规定,那么我们就需要自己手动添加特性了,如下代码所示,Student类包含了一个StandardRefId属性:

    public class Student
    {
        public Student() { }
    
        public int StudentId { get; set; }
        public string StudentName { get; set; }
    
        public int StandardRefId { get; set; }
            
        [ForeignKey("StandardRefId")]
        public virtual Standard Standard { get; set; }
    }
           
    public class Standard
    {
        public Standard()
        {
            StudentsList = new List<Student>();
        }
        public int StandardId { get; set; }
        public string Description { get; set; }
    
        public virtual ICollection<Student> Students { get; set; }
    }

    如果代码,我们必须要给Standard属性加上[ForeignKey("StandardRefId")]特性,这样创建数据库的时候才会将StandardRefId设置为外键,数据库如下:

    Entity Framework code-first example

    2.使用Fluent API配置One-to-Many关系:

    还是拿上面两个类的例子

    Student类和Standard类代码如下:

    public class Student
    {
        public Student(){ }
    
        public int StudentId { get; set; }
        public string StudentName { get; set; }
    
        public int StandardId { get; set; }
    
        public virtual Standard Standard { get; set; }
    }
           
    public class Standard
    {
        public Standard()
        {
            StudentsList = new List<Student>();
        }
        public int StandardId { get; set; }
        public string Description { get; set; }
    
        public virtual ICollection<Student> Students { get; set; }
    }

    使用Fluent API配置一对多关系代码:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
            //one-to-many 
            modelBuilder.Entity<Student>()
                        .HasRequired<Standard>(s => s.Standard) // Student entity requires Standard 
                        .WithMany(s => s.Students); // Standard entity includes many Students entities
    
    }

    这是默认两个类的外键命名都遵循约定命名情况的时候,如果Student类包含了一个不遵循约定命名的外键名称呢,如下所示:

    public class Student
    {
        public Student(){ }
    
        public int StudentId { get; set; }
        public string StudentName { get; set; }
    
        //StdId有一个不同于Code-First默认约定命名的名称
        public int StdId { get; set; }
    
        public virtual Standard Standard { get; set; }
    }
           
    public class Standard
    {
        public Standard()
        {
            StudentsList = new List<Student>();
        }
        public int StandardId { get; set; }
        public string Description { get; set; }
    
        public virtual ICollection<Student> Students { get; set; }
    }

    如上所示,StdId就没有遵循默认的<类型名称>Id的外键命名约定,所以我们的Fluent API配置如下:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
            //one-to-many 
            modelBuilder.Entity<Student>()
                        .HasRequired<Standard>(s => s.Standard)
                        .WithMany(s => s.Students)
                        .HasForeignKey(s => s.StdId);
    
    }

    如你所见, modelBuilder.Entity<Student>().HasRequired<Standard>(s => s.Standard) 特别指定Student实体的Standard属性不能为空, .WithMany(s => s.Students).HasForeignKey(s => s.StdId) 指定了Standard实体包含多个Student实体,而且外键为StdId。

    注意:每一个泛型方法都返回了一个该类型对象,所以才能有这种一串打点的写法^_^)

    所以针对上面的配置代码,我们也可以以Standard类开头来写配置代码,如下所示:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
            //configure one-to-many
            modelBuilder.Entity<Standard>()
                        .HasMany<Student>(s => s.Students) //Standard has many Students
                        .WithRequired(s => s.Standard)  //Student require one Standard
                        .HasForeignKey(s => s.StdId);//Student includes specified foreignkey property name for Standard
    }

    代码运行后将会创建如下的数据库:

    one-to-one relationship in code first

    注意StdId是不为空的列,所以每次加入和更新Students表的时候必须要指定Student实体类的Standard属性。

    在One-to-Many关系中配置可空外键:

    很简单,使用HasOptional方法代替HasRequired方法即可。

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
            //one-to-many 
            modelBuilder.Entity<Student>()
                        .HasOptional<Standard>(s => s.Standard)
                        .WithMany(s => s.Students)
                        .HasForeignKey(s => s.StdId);
    
    }

     这样,Students表的StdId列就可为空了。


    最近太忙了,工作上,生活上,总之,好事多磨吧,既然下定决心了要更下去,就不能食言。今天就先到这里吧,下篇将讲多对多关系的操作。

  • 相关阅读:
    LiveCharts文档-3开始-1安装
    LiveCharts文档-2FAQ
    时间戳的简介
    LiveCharts文档-1前言
    做了一个串口读写温度的程序
    CsvHelper文档-6类型转换
    CsvHelper文档-5配置
    如何选择 .NET Framework目标版本
    CsvHelper文档-4映射
    CsvHelper文档-3写
  • 原文地址:https://www.cnblogs.com/tang-tang/p/5572026.html
Copyright © 2020-2023  润新知