EF自我理解: 一对一 一对多 多对多
一,一对一关系。
如:一个student,对应一个studentDetail。
1,student类:
public class Student : FullAuditedAggregateRoot<long> { public virtual StudentDetail StudentDetail { get; set; }//包含一个studentDetail的导航属性后 EF会给两个表形成主外键关系。 }
2,studentDetail类
public class StudentDetail : FullAuditedAggregateRoot<long> { }
3,生成的表结构如下:
A表中的一个字段,是B表的主键,那他就可以是A表的外键。在这里,student表中,有一个字段是studentDetail表的主键,所以这个字段就是student表的外键。
二,一对多关系。
如:一个班级有多个学生。
1,student类:
public class Student : FullAuditedAggregateRoot<long> { public virtual StudentDetail StudentDetail { get; set; } public virtual BJClass BJClass { get; set; }//加这个方便访问student的时候把班级信息点出来 } }
2,班级类
/// <summary> /// 班级 /// </summary> public class BJClass : FullAuditedAggregateRoot<long> { public virtual ICollection<Student> Students { get; set; } }
3,生成的表结构:
student表:
班级表:
4,一对多中,一的那一方,要不要加上对多的那一方的导航属性?
比如:student类中,要不要加上 班级BJClass,加上跟不加对表结构生成有没有影响?
为了验证,这里增加一个student1类,跟上面student类只有一个地方不同,那就是没加BJClass的导航属性,注释掉了。
public class Student1 : FullAuditedAggregateRoot<long> { public virtual StudentDetail StudentDetail { get; set; } // public virtual BJClass1 BJClass1 { get; set; } //注释掉 } }
班级不变,只是改了类名:
/// <summary> /// 班级1 /// </summary> public class BJClass1 : FullAuditedAggregateRoot<long> { public virtual ICollection<Student1> Students { get; set; } }
生成的表结构:
班级表:
结论:在一对多关系中,在一 的那一方,加不加 多 的那一方的导航属性,对表结构的生成是没有影响的。
三,多对多。
如:一个学生可以有多门课程 一门课程可以被多个学生学习
学生表:
/// <summary> /// 学生表 /// </summary> public class Student : FullAuditedAggregateRoot<long> { public virtual StudentDetail StudentDetail { get; set; } public virtual BJClass BJClass { get; set; } public virtual ICollection<Course> Courses { get; set; } }
课程表:
/// <summary> /// 课程表 /// </summary> public class Course : FullAuditedAggregateRoot<long> { public virtual ICollection<Student> Students { get; set; } }
多对多,双方各自包含另一方的集合导航属性,数据库默认会生成中间表,生成的表结构如下:
这样生成的中间表,基本可以满足大部分的多对多的需求,但是如果有需要在中间表中添加一些字段,则这种根据EF默认配置的方法显然是无法满足的。
查了网上资料,说出了默认配置之外,还可以用FluentApi对中间表进行配置,但FluentApI配置的方式现在很多人都没怎么用过。
既然我们要在中间表增加字段,那我们为什么不直接自己配置中间表呢?就不需要EF帮我们做默认配置了。
多对多默认配置思路:
1,新建类A,A中包含B的集合导航属性
2,新建类B,B中也包含A的集合导航属性
3,EF默认生成中间表AB(但生成的中间表只是默认包含A的id以及B的id,无法按需添加字段)
多对多手动配置中间表思路:
1,新建中间表类AB,按需添加自己需要的字段。
2,新建类A,A中包含中间表AB的集合导航属性(不是包含B)
3,新建类B,B中同样包含中间表AB的集合导航属性。
示例:
一份同意书可以对应多个小服务,一个小服务可以被多个同意书选择。
中间表:
/// <summary> /// 自己配置中间表 /// </summary> public class ConsentFormeSmallService2 { /// <summary> /// 小服务id /// </summary> [Required] public virtual long ConsentFormeSmallService2Id { get; set; } /// <summary> /// 自己新增的字段 /// </summary> public virtual long MyFiled { get; set; } }
同意书表:
/// <summary> /// 同意书表 /// </summary> public class ConsentForme : AuditedEntity<long> { public ICollection<ConsentFromeItem> ConsentFromeItem { get; set; } // public ICollection<ConsentFormeSmallService> ConsentFormeSmallService { get; set; } public ICollection<ConsentFormeSmallService2> ConsentFormeSmallService2 { get; set; } }
小服务表:
/// <summary> /// 小服务表 /// </summary> public class SmallService : AuditedEntity<long> { // public ICollection<ConsentFormeSmallService> ConsentFormeSmallService { get; set; } public ICollection<ConsentFormeSmallService2> ConsentFormeSmallService2 { get; set; } }
生成的表结构,这里只看中间表:
如上所示,中间表中包含两个外键,分别是同意书表、小服务表的id。同时 还有自己按需添加的MyFIled字段,实现了中间表的按需添加。
如果不直接操作中间表,则可以不需要写到DBContext里面去: