实体框架,发布包含已存在对象集合的实体

本文关键字:实体 对象 集合 存在 布包含 框架 | 更新日期: 2023-09-27 18:31:27

一点背景,我在数据库中有 2 个表,它们通过连接表共享多对多关系。与此博客文章中概述的方案几乎相同。

我将使用一个非常简单的示例来说明我正在尝试做的事情。当我的 Web 应用程序上的用户想要创建订单时,他们有权访问要在发布之前添加到订单的产品列表。此产品列表通过 REST API 调用提取,并作为 JSON 数据提供给客户端应用。

当我发布订单时,我的问题出现了,实体框架工作试图将产品重新保存在我的集合中,而不仅仅是创建关联。

请考虑以下我的控制器和 UnitOfWork 类的极其简化的代码示例。

public class OrdersController : ApiController
{
   private readonly IUnitOfWork _unitOfWork;
   private readonly IOrderRepository _orderRepository;
   public OrdersController(IUnitOfWork unitOfWork, IOrderRepository orderRepository)
   {
       _unitOfWork = unitOfWork;
       _orderRepository = orderRepository;
   }
   // POST api/Orders
   public Dto.Get.Order Post(Dto.Post.Order postOrder)
   {
       Models.Order modelOrder = new Model.Order();
       modelOrder.Name = postOrder.Name;
       modelOrder.Description = postOrder.Description;
       foreach (var getProduct in postOrder.Products)
       {
           Models.Product modelProduct = new Models.Product();
           modelProduct.Id = getProduct.Id;
           getProduct.Name = getProduct.Name;
           getProduct.Price = getProduct.Price;
           modelOrder.Products.Add(modelProduct);
       }
       modelOrder.AccountId = 999;
       _orderRepository.Insert(modelOrder);
       _orderRepository.Save();
       _unitOfWork.SaveChanges();
       //Return new Order as it exists in DB
       return Get(modelOrder.Id);
   }
}
public class UnitOfWork : IUnitOfWork
{
   public MyApplicationContainer Context { get; set; }
   public UnitOfWork(MyApplicationContainer context)
   {
       Context = context;
       this.Context.Configuration.ProxyCreationEnabled = false;
       this.Context.Configuration.LazyLoadingEnabled = false;
   }
   public void SaveChanges()
   {
       Context.SaveChanges();
   }
   private bool disposed = false;
   protected virtual void Dispose(bool disposing)
   {
       if (!this.disposed)
           if (disposing)
               Context.Dispose();
       this.disposed = true;
   }
   public void Dispose()
   {
       Dispose(true);
       GC.SuppressFinalize(this);
   }
}

注意:为简单起见,我没有费心发布我的帖子和获取 DTO,或者我的订单和产品实体模型。

一个有趣的观察结果是,如果我根据传入的 ID 获取产品的模型版本,然后将其分配给要保存的集合,它工作正常。但这对我来说似乎非常"健谈",考虑到一个订单可能有数百种产品。例:

    foreach (var getProduct in postOrder.Products)
       {
          var modelProduct = _productRepository.Get(getProduct.Id);
           modelOrder.Products.Add(modelProduct);
       }

实体框架,发布包含已存在对象集合的实体

您正在使用 new 运算符显式创建新产品。显然,EF 尝试在数据库中创建新产品。您需要在数据库中查询产品,但您应该使用一个查询来完成。类似的东西

var productsIDs = postOrder.Products.Select(p => p.ID).ToArray();
var actualProducts = from p in product
                     where productsIDs.Contains(p.ID)
                     select p;