【问题标题】:EF Code First: duplicating data on save (many-to-many)EF Code First:在保存时复制数据(多对多)
【发布时间】:2023-04-04 21:56:02
【问题描述】:

我正在使用 Entity Framework,但遇到了关于多对多映射的绊脚石。 假设我有两个实体,订单和产品。

在我的订单实体中,我有:

int OrderID,
double OrderPrice
datetime OrderDate
ICollection<Product> Products
datetime DispactDate

等等……

然后在我的产品类中,我有

int ProductID
string ProductName
string ProductDescription

等等。

在我的 Code First EF DB 中,我有一个 Order 表,它很好地映射到我的订单,一个 products 表,其中包含可以订购的产品列表,然后使用 EF Code-first 迁移 EF 创建了带有外键的 OrderProducts 到两个主其他表的键。都很好。

但是,当我保存在其产品集合中有多个产品的订单时,EF 将复制产品表中的所有条目。因此,如果我添加产品 10、12 和 13,它会使用三个新 ID 创建三个新行并映射到它们,而不是原来的。如果我随后处理另一个包含另外 20 个现有产品的订单,那么产品表中将创建 20 个新条目!

在我的 DBContext 中,我已经覆盖了 onModelCreatingEvent:

modelBuilder.Entity<Order>()
                .HasMany(x=>x.Products)
                .WithMany()
                .Map(be =>
                    {
                        be.ToTable("OrderProducts");
                });

我猜这里配置有问题。我是从How to map many-to-many relationships in Entity Framework CTP5?得到这个的

以前我有两个独立的存储库 - 一个用于订单,一个用于产品。我现在已将这些合并到 orderRepository 中,它公开了 Orders 和 Products,以便我可以将产品附加到 orderRepository 上下文。 为了生成产品,我有一个控制器操作 AddProducts:

public RedirectToRouteResult Products(FormCollection selectedProducts)
        {
                currentOrder.Products = new List<Product>();
                foreach (string thisProduct in selectedProducts)
                {
                    int thisProductID = int.Parse(thisProduct);
                    Product selectedProduct = orderRepository.Products.Where(e => e.ProductID == thisProductID).FirstOrDefault();

                    if (selectedProduct != null)
                    {
                        orderRepository.AttachToContext(selectedProduct);
                        currentOrder.Products.Add(selectedProduct);
                    }                    
                }

                orderRepository.saveChanges(currentOrder);

}

【问题讨论】:

  • 您可以将代码发布到您要查找的位置并将产品添加到订单中吗?
  • 添加了我正在做的卢克示例。

标签: .net entity-framework


【解决方案1】:

我怀疑orderRepository 中的上下文实例与ProductsRepo 中的上下文实例不同。您应该首先在orderRepository 的上下文中将attach 的产品Products

顺便说一下,这是为什么每个实体的存储库会真正妨碍您的一个示例。如果您想使用存储库模式,通常最好考虑聚合根。

【讨论】:

  • 是的,这也是我的怀疑
  • 似乎没有帮助。 currentOrder.Products.Add(selectedProduct); 之前的行我添加了 ProductsRepo.AttachToContext(selectedProduct),它只是执行 context.Products.Attach(product);但值仍在重复。
  • 您必须附加到订单存储库中的上下文。
【解决方案2】:

您能否构建一个小单元测试,它只创建上下文、检索产品、创建订单并将检索到的产品添加到订单中?

这应该工作得很好。听起来您正在创建一个新的产品对象,而不是使用预先存在的产品对象。或者创建一个而不设置适当的实体键。

这听起来不像是从不同的上下文中获取它,因为您通常会收到警告说它已经附加到另一个上下文。

【讨论】:

    【解决方案3】:

    谢谢。设法解决了这个问题。在我的OrderRepository 中,我必须手动将每个Product 标记为EntitySate.Unchanged 状态。所以,在SaveOrder() 我现在这样做:

    foreach (Product product in Orders.Products)
    {
      context.Entry(product).State = System.Data.EntityState.Unchanged;
    }
    

    这很好,但我很好奇为什么当订单中的每个产品都已经分配了一个有效的(和现有的)productid 时我必须执行此步骤? 奇怪。

    【讨论】:

      猜你喜欢
      • 2013-02-07
      • 1970-01-01
      • 1970-01-01
      • 2011-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-20
      相关资源
      最近更新 更多