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


    配置一对一(One-to-One)关系:

    两个实体中,如果一个实体的一个实例与另一个实体相关,则我们就叫做一对一关系

    查看如下代码:

    public class Student
    {
        public Student() { }
    
        public int StudentId { get; set; }
        public string StudentName { get; set; }
    
        public virtual StudentAddress Address { get; set; }
    
    }
         
    public class StudentAddress 
    {
        public int StudentAddressId { get; set; }
            
        public string Address1 { get; set; }
        public string Address2 { get; set; }
        public string City { get; set; }
        public int Zipcode { get; set; }
        public string State { get; set; }
        public string Country { get; set; }
    
        public virtual Student Student { get; set; }
    }

    这里,Student类只能拥有零个或最多一个StudentAddress类,所以符合一对一关系

    在SQL Server数据库中,一对一关系发生在当一张表的主键是另一张表的主键或外键时,所以如上代码中,我们要配置StudentId为主键,StudentAddressId既为主键也为外键。

    1.使用DataAnnotations配置一对零或一对一关系:

    Student类会根据Code-First默认约定将StudentId属性配置为主键,所以这里我们就不用额外的配置它了。

    StudentAddress类中,我们需要配置StudentAddressId既为主键又为外键,同样的,Code-First默认约定会将StudentAddressId配置为主键,所以这里我们仅仅需要使用[ForeignKey("Student")]特性将StudentAddressId属性配置为外键即可。

    代码如下:

    public class Student
    {
        public Student() { }
    
        public int StudentId { get; set; }
        public string StudentName { get; set; }
    
        public virtual StudentAddress Address { get; set; }
    
    }
         
    public class StudentAddress 
    {
        [ForeignKey("Student")]
        public int StudentAddressId { get; set; }
            
        public string Address1 { get; set; }
        public string Address2 { get; set; }
        public string City { get; set; }
        public int Zipcode { get; set; }
        public string State { get; set; }
        public string Country { get; set; }
    
        public virtual Student Student { get; set; }
    }
    View Code

    这样,Student类和StudentAddress类就配置好了一对一关系。

    如果StudentAddressId名称改变了,比如下面代码,改成了StudentId,默认就不会创建主键了,需要手动添加上[Key]特性:

    public class Student
    {
        public Student() { }
    
        public int StudentId { get; set; }
        public string StudentName { get; set; }
    
        public virtual StudentAddress Address { get; set; }
    
    }
         
    public class StudentAddress 
    {
        [Key, ForeignKey("Student")]
        public int StudentId { get; set; }
            
        public string Address1 { get; set; }
        public string Address2 { get; set; }
        public string City { get; set; }
        public int Zipcode { get; set; }
        public string State { get; set; }
        public string Country { get; set; }
    
        public virtual Student Student { get; set; }
    }
    View Code

    这样,StudentAddress类中的StudentId就被配置为既是主键,又是外键。

    注意: 虽然Student类中包含StudentAddress类属性,StudentAddress类中也包含Student类属性,但Student类的StudentAddress类属性可以为空,而StudentAddress类的Student类属性不能为空!如果保存一个Student类属性为空的StudentAddress类,会抛出异常。

    2.使用Fluent API配置一对零或一对一关系:

    下面我们将不使用任何DataAnnotations特性(虽然它们可以一起使用)仅仅使用Fluent API来配置一对一关系。

    当Student类的命名和StudentAddress类的命名遵循默认约定的时候:

    既然默认约定会自动为Student和StudentAddress创建主键,所以这里我们仅仅需要把StudentAddressId配置为外键

    代码如下:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        
        // Configure Student & StudentAddress entity
        modelBuilder.Entity<Student>()
                    .HasOptional(s => s.Address) // Mark Address property optional in Student entity
                    .WithRequired(ad => ad.Student); // mark Student property as required in StudentAddress entity. Cannot save StudentAddress without Student
    
    }

    上面代码中,Student实体的Address属性使用了HasOptional()方法,即Address属性不是必须的,可为空,又为StudentAddress类的Student属性使用了WithRequired()方法,即Student属性为必填,不能为空,如果存储StudentAddress实体的时候发现Student属性为空,则会抛出异常。

    这样配置以后,StudentAddressId就已经是外键了。

    当StudentAddress类的命名不遵循默认约定的时候:

    如下代码,我们想要StudentAddress类的StudentId属性成为主外键

    public class Student
    {
        public Student() { }
    
        public int StudentId { get; set; }
        public string StudentName { get; set; }
    
        public virtual StudentAddress Address { get; set; }
    
    }
         
    public class StudentAddress 
    {
        public int StudentId { get; set; }
            
        public string Address1 { get; set; }
        public string Address2 { get; set; }
        public string City { get; set; }
        public int Zipcode { get; set; }
        public string State { get; set; }
        public string Country { get; set; }
    
        public virtual Student Student { get; set; }
    }

    Fluent API配置如下:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // Configure StudentId as PK for StudentAddress
        modelBuilder.Entity<StudentAddress>()
            .HasKey(e => e.StudentId);
            
        // Configure StudentId as FK for StudentAddress
        modelBuilder.Entity<Student>()
                    .HasOptional(s => s.Address) 
                    .WithRequired(ad => ad.Student); 
    
    }

     

    3.使用Fluent API配置一对一关系:

    说白了,所谓的一对一关系,即是两个实体类中作为主外键的类属性都不能为空。

    注意:一对一关系在SQL Server中并不是必须,通常使用一对零或一对一。

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // Configure StudentId as PK for StudentAddress
        modelBuilder.Entity<StudentAddress>()
            .HasKey(e => e.StudentId);
            
        // Configure StudentId as FK for StudentAddress
        modelBuilder.Entity<Student>()
                    .HasRequired(s => s.Address) 
                    .WithRequiredPrincipal(ad => ad.Student); 
    
    }

    在上面的代码中, modelBuilder.Entity<Student>().HasRequired(s => s.Address)使得Student类的Address属性为必须,WithRequiredPrincipal(ad => ad.Student) 方法使的StudentAddress类的Student属性为必须。

    注意:这里主要的实体类是Student,依赖的实体类是StudentAddress。

    DataAnnotations and Fluent API都会创建如下的一对零或一对一关系的数据库:

    one-to-one relationship in code first

    我们可以检查Student表和StudentAddress表之间的关系:

    one-to-one relationship in code first

    图表关系如下

    one-to-one relationship in code first

     啊啊啊啊啊,虽然最近忙成狗,但是说好的翻译,一定会坚持下去的!!!

  • 相关阅读:
    sql常用函数
    sql数据库查询
    数据库增删改查
    数据库基本概念
    C#总结
    C#结构体
    C#常用函数类
    初识函数
    C#冒泡排序 折半查找
    12月27日笔记
  • 原文地址:https://www.cnblogs.com/tang-tang/p/5568305.html
Copyright © 2020-2023  润新知