c# - 为多对多关系创建默认关系对象,并在我的数据库上下文中保持更改?
问题描述
我想要做什么:当用户选择一个产品时,用每个产品填充一个数据网格。如果该产品/事件组合具有关联的 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; }
}
我通过查询我的产品并将其连接到我的 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 时,它会按预期工作,并且用户可以编辑分配的数量(已售和采样在此视图中被锁定):
我的问题是储蓄。现在我正在遍历数据网格的每一行,如果它已被更改或者值不为空,请从中创建一个 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 的引用在我的调试器中都是填充的、有效的和正确的。
几天来,我一直被困在这个问题的各个方面,我知道我的方法是错误的,任何建议都将不胜感激。
解决方案
我想你的问题是EventProduct
你添加到你的DbContext
引用一个Event
或Product
(或两者)已经存在于数据库中,但当前没有被DbContext
. 当调用dbContext.EventProducts.Add(entry.EventProduct);
它时,它会尝试添加entry.EventProduct.Event
and 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();
注意:根据文档,您附加的实体将获得状态Unchanged
,这意味着如果您确实对数据库进行了更改,Event
或者Product
您想要在数据库中更新,您应该使用DbContext.Entry()并将返回的Entry.State设置为Modified
.
推荐阅读
- firebase - 为什么我不能将 ENV 变量与 Firebase 函数一起使用
- vb.net - VB.NET/Access - 在表格中为每个学生添加重复条目,并在 Datagridview 中显示每个学生的重复项总数
- c++ - 交换指向对象的指针向量以输出交换的对象
- gradle - Gradle protobuf 任务未从依赖项中获取定义
- r - 如何通过唯一组/子组对找到不等式的总和?
- c# - 额外的列仍然显示在 Datagrid 中?
- awk - 为什么我的 awk 命令将字符串添加到开头而不是最后追加
- android-studio - Cordova Crosswalk:安装 Andoird-apk 失败
- xamarin - ZXing.Mobile.Net.Forms ZXing.Result 类型问题
- fortran - 我想制作一个矩阵(6,6),但它显示了其他值(用于牛顿插值)