为多对多关系创建默认关系对象,并在我的数据库上下文中保留更改?
Creating default relational objects for a many-to-many relationship, and keeping changes in my database context?
我想做什么:当用户选择产品时,用每个产品填充数据网格。如果该产品/事件组合具有关联的 EventProduct,则使用该数据填充数据网格的其他部分。如果不是,则创建一个新的 EventProduct 并将所有属性默认为 0。在保存事件时,如果 EventProduct 属性已更改或已填充,请将该 EventProduct 作为新的 EventProduct 保存到数据库中。
我目前的做法:
我有三个 类:此处定义的 Event、Product 和 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; }
}
我正在填充 table,方法是查询我的产品并将其加入我的 EventProduct,然后创建一个新的关联对象,该对象具有一对一关系的产品和 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 时,它会按预期工作,并且用户可以编辑分配数量(已售出和抽样在此视图中被锁定):
我的问题是保存。现在我正在遍历数据网格的每一行,如果它被更改或者值不为空,则从中创建一个 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 时,我收到错误消息,“'发生引用完整性约束违规:主键 属性 是引用完整性约束的一部分,当从属时无法更改对象是不变的,除非它被设置为关联的主体对象。主体对象必须被跟踪并且不被标记为删除。'”。这对我来说没有意义,因为它对 Product 和 Event 的引用在我的调试器中都已填充、有效且正确。
几天来我一直被这个问题的各个部分所困,我知道我的方法是错误的,任何建议将不胜感激。
我想你的问题是你添加到 DbContext
的 EventProduct
指的是已经存在于数据库,但当前未被 DbContext
跟踪。当调用 dbContext.EventProducts.Add(entry.EventProduct);
时,它的效果是它试图在 DbContext
中添加 entry.EventProduct.Event
和 entry.EventProduct.Product
,就好像它们是新实体一样。
如果您知道 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();
注意:根据the documentation the entities you attach will be given the state Unchanged
which means if you do have changes to the Event
or Product
that you want to update in the database you should instead use DbContext.Entry() and set the returned Entry.State至Modified
。
我想做什么:当用户选择产品时,用每个产品填充数据网格。如果该产品/事件组合具有关联的 EventProduct,则使用该数据填充数据网格的其他部分。如果不是,则创建一个新的 EventProduct 并将所有属性默认为 0。在保存事件时,如果 EventProduct 属性已更改或已填充,请将该 EventProduct 作为新的 EventProduct 保存到数据库中。
我目前的做法: 我有三个 类:此处定义的 Event、Product 和 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; }
}
我正在填充 table,方法是查询我的产品并将其加入我的 EventProduct,然后创建一个新的关联对象,该对象具有一对一关系的产品和 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 时,它会按预期工作,并且用户可以编辑分配数量(已售出和抽样在此视图中被锁定):
我的问题是保存。现在我正在遍历数据网格的每一行,如果它被更改或者值不为空,则从中创建一个 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 时,我收到错误消息,“'发生引用完整性约束违规:主键 属性 是引用完整性约束的一部分,当从属时无法更改对象是不变的,除非它被设置为关联的主体对象。主体对象必须被跟踪并且不被标记为删除。'”。这对我来说没有意义,因为它对 Product 和 Event 的引用在我的调试器中都已填充、有效且正确。
几天来我一直被这个问题的各个部分所困,我知道我的方法是错误的,任何建议将不胜感激。
我想你的问题是你添加到 DbContext
的 EventProduct
指的是已经存在于数据库,但当前未被 DbContext
跟踪。当调用 dbContext.EventProducts.Add(entry.EventProduct);
时,它的效果是它试图在 DbContext
中添加 entry.EventProduct.Event
和 entry.EventProduct.Product
,就好像它们是新实体一样。
如果您知道 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();
注意:根据the documentation the entities you attach will be given the state Unchanged
which means if you do have changes to the Event
or Product
that you want to update in the database you should instead use DbContext.Entry() and set the returned Entry.State至Modified
。