前言
此文章只是为了给新手程序员,和经验不多的程序员,在学习ef和lambada表达式的过程中可能遇到的问题。
本次使用订单表和员工表建立多对多关系。
首先是订单表:
public class Order { public int OrderId { get; set; } public string OrderTitle { get; set; } public string CustomerName { get; set; } public DateTime TransactionDate { get; set; } [ConcurrencyCheck] [Timestamp] public byte[] TimeStamp { get; set; } public virtual ICollectionInvolvedEmployees { get; set; } }
接下来是员工表:
public class Employee { public int EmployeeId { get; set; } public string EmployeeName { get; set; } public virtual ICollectionOrders { get; set; } }
映射文件(mapping):
public class OrderMap:EntityTypeConfiguration{ public OrderMap() { this.HasKey(o => o.OrderId); //OrderId为自增长 this.Property(o => o.OrderId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); this.Property(o => o.OrderTitle).IsRequired().HasMaxLength(64);//订单名称为必填,最大长度为64; this.Property(o => o.CustomerName).IsRequired().HasMaxLength(64);//订单名称为必填,最大长度为64; this.Property(o => o.TransactionDate).IsRequired(); //订单名称为必填,最大长度为64; } }
public class EmployeeMap:EntityTypeConfiguration{ /// /// 构造函数 /// public EmployeeMap() { this.HasKey(x => x.EmployeeId); this.ToTable("Employees"); this.Property(x => x.EmployeeName).IsRequired().HasMaxLength(20); //设置多对多的关系 .Map()配置用于存储关系的外键列和表。 /* Employees HasMany此实体类型配置一对多关系。对应Orders实体 WithMany 将关系配置为 many:many,且在关系的另一端有导航属性。 * MapLeftKey 配置左外键的列名。左外键指向在 HasMany 调用中指定的导航属性的父实体。 * MapRightKey 配置右外键的列名。右外键指向在 WithMany 调用中指定的导航属性的父实体。 */ this.HasMany(x => x.Orders). WithMany(x => x.InvolvedEmployees). Map(m => m.ToTable("EmployeeOrder"). MapLeftKey("EmployeeId"). MapRightKey("OrderId")); } }
dbcontext文件:
public class EfCodeFirstWithManyDbContext:DbContext { public EfCodeFirstWithManyDbContext() : base("DefaultConnection") { } public IDbSetOrderses { get; set; } public IDbSet Employeees { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new OrderMap()); modelBuilder.Configurations.Add(new EmployeeMap()); base.OnModelCreating(modelBuilder); } }
生成数据库:
数据库关系图:
基础工作建立完毕。
正文:
我们都知道在codefirst 配置多对多关系的时候,会自动给我买生成中间表。
在modelfirst和datafirst的时候都会生成一个中间类:EmployeeOrder.cs
而codefirst不会生成这个类,本文所阐述的就是使用在codefirst中使用ef、lambada表达对其进行增删改查的多种情况
-
创建一个订单
-
添加订单信息、员工信息到数据表中,建立两则多对多的联系
-
清空中间表之间的数据,而不影响employee和order表中的数据
-
给中间表添加数据,给两个已经存在的数据建立中间关系
-
操作中间表,修改两个表employee和order中值,并且删除中间表中多余的值
本文大概操作次5种情况。
代码:
//添加订单信息、员工信息到数据表中,建立两则多对多的联系 public static void CreateFullOrderByEmployee() { #region 添加订单信息、员工信息到数据表中,建立两则多对多的联系 using (var dbContext = new EfCodeFirstWithManyDbContext()) { var order = new Order { OrderTitle = "购买汽车", CustomerName = "梁桐铭", TransactionDate = DateTime.Now, InvolvedEmployees = new List() }; var employee1 = new Employee {EmployeeName = "管理员-yoyocms", Orders = new List ()}; var employee2 = new Employee {EmployeeName = "主管-yoyocms", Orders = new List ()}; //先保存订单到数据库中 dbContext.Orderses.Add(order); order.InvolvedEmployees.Add(employee1); //order.InvolvedEmployees.Add(employee2); // employee2.Orders.Add(order); var res = dbContext.SaveChanges(); } #endregion }
为了测试方便对这个方法for循环了20次:
private static void Main(string[] args) { for (int i = 0; i < 20; i++) { CreateFullOrderByEmployee(); } Console.WriteLine("加载完毕,请点击任意键退出"); Console.ReadKey(); }
清空中间表信息,而不影响order表和employee表的信息
//清空两个中间表之间的关系 public static void EmptyEmployeeOrder() { using (var dbContext = new EfCodeFirstWithManyDbContext()) { //获取到employeeId为20下,所有Orders订单列表信息和员工信息。 var employeeToUpdate = dbContext.Employeees.Include(x => x.Orders).FirstOrDefault(x => x.EmployeeId == 20); if (employeeToUpdate != null) { employeeToUpdate.Orders = new List(); dbContext.SaveChanges(); } else { Console.WriteLine("查询失败EmptyEmployeeOrder为空"); } } }
建立员工表和对应的订单表中建立两个表之间的联系
//建立两个已经存在的数据建立中间关系 public static void AddInfoEmployeeOrder() { using (var dbContext = new EfCodeFirstWithManyDbContext()) { //获取到employeeId为20下,所有Orders订单列表信息和员工信息。 var employeeToAdd = dbContext.Employeees.Include(x => x.Orders).FirstOrDefault(x => x.EmployeeId == 20); //设计订单表的集合,将新增的数据填充进来 int[] orderIdList = {13, 14, 15, 16, 17, 18, 19}; //判断employeeToAdd.Orders中是否有重复的OrderId if (employeeToAdd != null) { //查询出目前员工对应的订单表 var employeeOrder = new HashSet<int>(employeeToAdd.Orders.Select(e => e.OrderId)); foreach (var order in dbContext.Orderses) { //即将要添加orderIdList值的是否包含订单表的id //筛选出orderidList和orders中共同的值,添加到order.OrderId if (orderIdList.Contains(order.OrderId)) { //查询出目前employee表中的orderId是否包含了orderIdList中的id if (employeeOrder.Contains(order.OrderId)) { //打印出重复的orderId Console.WriteLine("重复的ID为" + order.OrderId); Console.WriteLine("不执行添加结果"); } else { //打印出Employee表中没有orderId Console.WriteLine("即将添加的值" + order.OrderId); //添加重复的值 employeeToAdd.Orders.Add(order); } } } } else { Console.WriteLine("employeeToAdd信息为空"); } dbContext.SaveChanges(); } }
修改两个表employee和order中值,并且删除多余的值
////// 修改两个表employee和order中值,并且删除多余的值 /// public static void UpdateInfoEmployeeOrder() { //首先获取到EmployeeId=20中,所有的Orders列表和employee信息 using (var dbContext = new EfCodeFirstWithManyDbContext()) { var employeeUpdate = dbContext.Employeees.Include(x => x.Orders).FirstOrDefault(x => x.EmployeeId == 20); //需要更改对应的OrderId列表 int[] orderIdList = {13, 14, 15, 16, 17, 18, 19}; if (employeeUpdate != null) { //获取employee中的OrderIdlist var employeeOrderIdList = new HashSet<int>(employeeUpdate.Orders.Select(e => e.OrderId)); foreach (var order in dbContext.Orderses) { //判断要修改的Orderid和Orders表中的均包含 if (orderIdList.Contains(order.OrderId)) { if (!employeeOrderIdList.Contains(order.OrderId)) { Console.WriteLine("修改对应的订单Id表" + order.OrderId); employeeUpdate.Orders.Add(order); } } else { if (employeeOrderIdList.Contains(order.OrderId)) { Console.WriteLine("删除无用的订单表id"+order.OrderId); employeeUpdate.Orders.Remove(order); } } } } else { Console.WriteLine("查无employeeUpdate 的信息"); } dbContext.SaveChanges(); } }
尾声
至此操作实现了对codefirst中,对中间表的CRUD过程。
源代码下载