C# 为多对多关系创建默认关系对象,并在数据库上下文中保留更改?

C# 为多对多关系创建默认关系对象,并在数据库上下文中保留更改?,c#,entity-framework,entity-framework-6,relational-database,C#,Entity Framework,Entity Framework 6,Relational Database,我想做的是:当用户选择一个产品时,用每个产品填充一个数据网格。如果该产品/事件组合具有关联的EventProduct,则使用该数据填充数据网格的其他部分。如果没有,请创建新的EventProduct并将所有属性默认为0。保存事件时,如果EventProduct属性已更改或已填充,请将该EventProduct作为新的EventProduct保存到DB 我目前的做法是: 我有三个类:事件、产品和这里定义的EventProduct public partial class Event { [S

我想做的是:当用户选择一个产品时,用每个产品填充一个数据网格。如果该产品/事件组合具有关联的EventProduct,则使用该数据填充数据网格的其他部分。如果没有,请创建新的EventProduct并将所有属性默认为0。保存事件时,如果EventProduct属性已更改或已填充,请将该EventProduct作为新的EventProduct保存到DB

我目前的做法是: 我有三个类:事件、产品和这里定义的EventProduct

public partial class Event
{
   [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
   public Event()
   {
      EventProducts = new HashSet<EventProduct>();
   }

   [Key]
   public int index { get; set; }

   [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
   public virtual ICollection<EventProduct> EventProducts { get; set; }

}

public partial class Product
{
   [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
   public Product()
   {
      EventProducts = new HashSet<EventProduct>();
   }

   [Key]
   public int index { get; set; }
   [StringLength(200)]
   public string name { get; set; }

   [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
   public virtual ICollection<EventProduct> EventProducts { get; set; }
}

public partial class EventProduct
    {
        public EventProduct()
        {
            Event = new Event();
            Product = new Product();
            quantity_allocated = 0;
            quantity_sold = 0;
            quantity_sampled = 0;
        }
        public int index { get; set; }
        public int EventID { get; set; }
        public int ProductID { get; set; }
        public int? quantity_allocated { get; set; }
        public int? quantity_sold { get; set; }
        public decimal? quantity_sampled { get; set; }

        public virtual Event Event { get; set; }
        public virtual Product Product { get; set; }
    }
我通过查询我的产品并将其连接到我的EventProducts,并创建一个新的关联对象来填充表,该对象的Product和EventProduct具有一对一的关系。我正在将itemsource设置为以下值:

public static List<ProductEventProduct> GetProductEventProduct(Event e, DatabaseModel dbContext)
{
   var query = from product in dbContext.Products
               join eventProduct in dbContext.EventProducts
                     on new { pIndex = product.index, eIndex = e.index }
                        equals new { pIndex = eventProduct.Product.index, eIndex = eventProduct.Event.index } into temp
               from eventProduct in temp.DefaultIfEmpty()
               select new ProductEventProduct
               {
                     Product = product,
                     EventProduct = eventProduct
               };
   var dataSource = query.ToList();
   foreach (ProductEventProduct entry in dataSource)
   {
         if (entry.EventProduct == null)
         {
            entry.EventProduct = new EventProduct()
            {
               EventID = e.index,
               ProductID = entry.Product.index,
               Product = entry.Product,
               Event = e
            };
         }
   }
   return dataSource;
}
当我的数据源EventProduct中有一个单独的手动输入时,它会按预期工作,用户可以编辑分配的销售金额,并在该视图中锁定采样:

我的问题是存钱。现在,我正在遍历数据网格的每一行,如果它已更改或值不为null,请从中创建一个EventProduct,并将该EventProduct添加到我的数据库上下文中:

List<Associations.ProductEventProduct> entries = (List<Associations.ProductEventProduct>)EventProductDataGrid.ItemsSource;
IEnumerable<Associations.ProductEventProduct> changedEntries = entries.Where(association =>
   association.EventProduct.quantity_allocated != 0 ||
   association.EventProduct.quantity_sampled != 0 ||
   association.EventProduct.quantity_sold != 0);
foreach (Associations.ProductEventProduct entry in changedEntries)
{
   // if there are no event products in the database that have the same product and event, it's new so save it to DB
   if (!(dbContext.EventProducts.Any(ep =>
      ep.EventID == entry.EventProduct.EventID && ep.ProductID == entry.Product.index)))
   {
      dbContext.EventProducts.Add(entry.EventProduct); // line where I get the error described below
      dbContext.SaveChanges();
   }
   else // if it is an EventProduct which exists in the database already
   {
      EventProduct modifyEvent = dbContext.EventProducts.Single(ep => ep.Event.index == entry.EventProduct.Event.index && ep.Product.index == entry.Product.index);
      modifyEvent.quantity_allocated = entry.EventProduct.quantity_allocated;
      modifyEvent.quantity_sampled = entry.EventProduct.quantity_sampled;
      modifyEvent.quantity_sold = entry.EventProduct.quantity_sold;
   }
}
dbcontext.SaveChanges();
但将EventProduct添加到DBContext时,出现错误,“发生了引用完整性约束冲突:当依赖对象未更改时,作为引用完整性约束一部分的主键属性无法更改,除非将其设置为关联的主对象。”。必须跟踪主对象,并且不标记为删除。“。这对我来说毫无意义,因为它对产品和事件的引用都在我的调试器中填充、有效且正确


我已经在这个问题上纠缠了好几天了,我知道我的方法是错误的,任何建议都将不胜感激。

我想您的问题是,您添加到DbContext的EventProduct指的是数据库中已存在但DbContext当前未跟踪的事件或产品或两者。调用dbContext.EventProducts.Addentry.EventProduct时;其效果是,它试图将entry.EventProduct.Event和entry.EventProduct.Product添加到DbContext中,就像它们是新实体一样

如果您知道entry.EventProduct.Event和entry.EventProduct.Product已存在于数据库中,则可以将它们添加到更改跟踪器中,让EF知道它们已存在且未更改:

// Let EF know the entities already exist
dbContext.Set<Event>().Attach(entry.EventProduct.Event);
dbContext.Set<Product>().Attach(entry.EventProduct.Product);

// Now add the EventProduct letting it refer to the existing Event and Product
dbContext.EventProducts.Add(entry.EventProduct);
dbContext.SaveChanges();

注意:根据您附加的实体,其状态将保持不变,这意味着如果您对要在数据库中更新的事件或产品进行了更改,则应改为使用并将返回的设置为“已修改”。

谢谢,这为该问题提供了很多信息。现在我已经在一个上下文中创建了一个方法,其中事件是常量,循环所有产品,foreach产品检查是否有关联的EventProduct。如果有,它会将EventProduct添加到列表中。如果没有,它将使用属性defaults以及事件和产品创建它,并将其添加到方法返回的列表中。它比我尝试过的任何其他方法都好,但是在向dbContext添加新的EventProducts时,我遇到了引用完整性约束冲突。我是否应该检查事件/产品是否存在?@rook218如果在添加EventProduct时不知道数据库中是否已经存在该事件和产品,则需要检查dbContext.Events.Any。。。等等。首先,是的。但我建议您尝试设计您的系统,使您提前了解这一点。例如,您应该能够对以下问题回答“否”:我是否会创建一个新的EventProduct,它将引用一个不存在的事件或产品?在我运行此功能的上下文中,我肯定知道产品和事件都存在。我的问题主要是,我从我的事件对象创建了大部分表单,然后分别创建了8个左右的EventProducts,并试图分别保存它们。现在我只使用Event和Event.EventProducts属性,它工作得更好了。解决这个问题的方法是,我不是一个傻瓜,而是实际使用MVVM设计,而不是试图绕过它,在UI组件中处理业务逻辑。