本文主要讲EF一对多关系和多对多关系的建立
一、模型设计器
1、一对多关系
右键设计器新增关联
导航属性和外键属性可修改
2、多对多关系
右键设计器新增关联
模型设计完毕之后,根据右键设计器根据模型生成数据库,就能生成对应的表之间的一对多和多对多关联
二、代码层面
建表语句如下:
--建表脚本create table Student( Id int not null, Name varchar(30) not null, Age int not null)create table Teacher( Id int not null, Name varchar(30) not null, Age int not null)create table StudentTeacher( StudentId int not null, TeacherId int not null)create table InfoCard( Id int not null, [Money] int not null, StudentId int not null)
添加常规主键约束,代码如下:
--单主键约束alter table Student add constraint [PK_People]primary key clustered (Id Asc)alter table InfoCard add constraint [PK_InfoCard]primary key clustered (Id Asc)alter table Teacher add constraint [PK_Teacher]primary key clustered (Id Asc)
1、一对多(通过外键)
--但外键约束(一对多)alter table InfoCard add constraint [FK_InfoCard_Student]foreign key (StudentId) references Student (Id) on delete no action on update no action
2、多对多(中间表双主键双外键)
--双主键约束(多对多)alter table StudentTeacher add constraint [PK_StudentTeacher]primary key clustered (StudentId,TeacherId Asc)--双外键约束(多对多)alter table StudentTeacheradd constraint [FK_StudentTeacher_Student]foreign key (StudentId) references Student (Id) on delete no action on update no action --级联更新级联删除alter table StudentTeacher add constraint [FK_StudentTeacher_Teacher]foreign key (TeacherId) references Teacher (Id) on delete no action on update no action
生成对应的一对多和多对多关联的表之后,根据数据库生成模型就能生成对应的模型
三、多对多无载荷
根据上面的建表语言,我们能得出Teacher表和Student表在数据库中的关系如下图:
数据库关系图:
在模型设计器中的关系如下图:
模型设计图:
观察二图的区别,发现数据库表关系图中的StudentTeacher(链接表)没有出现在模型设计器中。原因如下:
因为链接表没有标量属性(没有载荷),实体框架认为它存在的唯一价值就是联结Teacher和Student,没有标量属性的联结表,在各自的实体中将以ICollection集合的形式出现.
当然如果链接表有标量属性,那么模型设计器就会创建一个完成的类来表示链接表。
四、多对多无载荷增改
// 添加demo using (var context = new EF6RecipeEntities()) { //给一个Teacher添加几个Student var teacher1 = new Teacher { Id=1, Name = "张老师", Age = 30 }; var stu1 = new Student { Id = 2, Name = "张三", Age = 20 }; var stu2 = new Student { Id = 3, Name = "李四", Age = 21 }; context.Teacher.Add(teacher1);//添加老师teacher1 teacher1.Student.Add(stu1);//给老师添加学生stu1 teacher1.Student.Add(stu2);//给老师添加学生stu2 //给一个Student添加几个Teacher var stu3 = new Student { Id = 4, Name = "小超", Age = 23 }; var t2 = new Teacher { Id = 5, Name = "王老师", Age = 33 }; var t3 = new Teacher { Id = 6, Name = "赵老师", Age = 36 }; context.Student.Add(stu3); stu3.Teacher.Add(t2); stu3.Teacher.Add(t3); context.SaveChanges(); } //遍历所有老师下面的所有学生 using (var context = new EF6RecipeEntities()) { DbSetts = context.Teacher; foreach (var t in ts) { Console.WriteLine("姓名:{0},年龄:{1},职位:{2},其管理的学生如下:", t.Name, t.Age, "老师"); var stus = t.Student; foreach (var s in stus) { Console.WriteLine("姓名:{0},年龄:{1},职位:{2}", s.Name, s.Age, "学生"); } Console.WriteLine(); } } Console.ReadKey();
五、多对多有载荷
上面学生和老师的例子并不能很好的说明多对多有载荷的问题,所以换成订单和产品,所以链接表将会产生一个订单数量的载荷(也就是链接表多了一个标量属性),
模型设计图如下:
有载荷的多对多关系比无载荷的多对多关系更加的简介明了。因为实体框架不支持在关联上附加载荷,所以有载荷的联结将会生成一个新的实体.
因为这个附加的载荷,Order需要通过OrderItem来获取与其关联的Product的项.
六、多对多有载荷增查
//添加 using (var context = new EF6RecipeEntities()) { var product = new Product { Id = 1, Desc = "面包", Price = 10 }; var order = new Order { Id = 10, OrderDate = DateTime.Now }; var orderItem1 = new OrderItem { Order = order, Product = product, Count = 1 }; product = new Product { Id = 2, Desc = "牛奶", Price = 11 }; var orderItem2 = new OrderItem { Order = order, Product = product, Count = 2 }; product = new Product { Id = 3, Desc = "牛奶面包", Price = 11 }; var orderItem3 = new OrderItem { Order = order, Product = product, Count = 1 }; context.OrderItems.Add(orderItem1); context.OrderItems.Add(orderItem2); context.OrderItems.Add(orderItem3); context.SaveChanges(); } //遍历 using (var context = new EF6RecipeEntities()) { foreach (var order in context.Orders) { Console.WriteLine("订单编号:{0},下单日期:{1},订单详情如下:",order.Id,order.OrderDate.ToShortDateString()); foreach (var oi in order.OrderItem) { Console.WriteLine("产品Id:{0},产品描述:{1},产品数量:{2},产品价格:{3}", oi.Product.Id,oi.Product.Desc,oi.Count,oi.Product.Price); } Console.WriteLine(); } } Console.ReadKey();
七、关于使用多对多有载荷还是多对多无载荷的意见
如果你有一个无载荷的多对多关系时,你可以考虑通过增加一标识列将其改变为有载荷的多对多关系。当你导入表到你的模型时,你将得到两个包含一对多关系的实体,这意味着,你的代码为将来有可能出现的多载荷做好了准备。增加一整型标识列的代价通常很小,但给模型带来了更大的灵活性。