EF基础知识小记五(一对多、多对多处理)
本文主要讲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 StudentTeacher add 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()) { DbSet<Teacher> ts = 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();
七、关于使用多对多有载荷还是多对多无载荷的意见
如果你有一个无载荷的多对多关系时,你可以考虑通过增加一标识列将其改变为有载荷的多对多关系。当你导入表到你的模型时,你将得到两个包含一对多关系的实体,这意味着,你的代码为将来有可能出现的多载荷做好了准备。增加一整型标识列的代价通常很小,但给模型带来了更大的灵活性。