【发布时间】:2014-07-02 21:00:30
【问题描述】:
在为我的 Entity Framework 存储库编写更新方法时,我包含以下代码:
public bool UpdateProduct(int id, Models.Product product)
{
Product ctxProduct = GetProductIncludingProductLists(id); //Pulls directly from context
if (ctxProduct != null && product != null)
{
/*Update ctxProduct fields using product*/
_ctx.Entry(ctxProduct).State = EntityState.Modified; //_ctx is my DbContext
return true;
}
return false;
}
但是我将实体的状态设置为修改的代码行会引发以下错误:
EntityFramework.dll 中出现“System.InvalidOperationException”类型的第一次机会异常
附加类型为“..Product”的实体失败,因为同一类型的另一个实体已经具有相同的主键值。如果图中的任何实体具有冲突的键值,则在使用“附加”方法或将实体的状态设置为“未更改”或“已修改”时,可能会发生这种情况。这可能是因为某些实体是新实体,尚未收到数据库生成的键值。在这种情况下,使用“添加”方法或“已添加”实体状态来跟踪图形,然后将非新实体的状态设置为“未更改”或“已修改”。
我对这条错误消息试图告诉我的内容感到困惑。由于我已将此条目从上下文中删除,因此它的主键应该与之冲突的唯一事物就是它本身。另外,我知道这个条目已经被分配了一个 id,因为我使用它的 id 访问它。
最后,我将这个条目的状态设置为 modified 的原因是因为调用 _ctx.saveChanges() 会返回 0,这表明上下文不知道我已经更改了任何内容(当我更改时)。
谁能解释为什么会抛出这个错误以及我需要做些什么来让上下文知道我的更改?
编辑
GetProductIncludingProductLists(id):
public Product GetProductIncludingProductLists(int id)
{
try
{
return _ctx.Products.Include("ProductLists")
.ToList()
.Select(p => new Product()
{
ProductId = p.ProductId,
CUSIP = p.CUSIP,
SEDOL = p.SEDOL,
BUID = p.BUID,
Key = p.Key,
Track = p.Track,
ProductLists = ((p.ProductLists.Select(l => new ProductList()
{
ProductListId = l.ProductListId,
Name = l.Name,
Products = null
})
.ToList() as List<ProductList>) ?? null)
})
.First(item => item.ProductId == id);
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
return null;
}
}
之所以会出现疯狂的select语句,是因为产品和产品列表是N:N相关的,不包括它们会导致'循环序列化'出错
【问题讨论】:
-
能否请包含 GetProductIncludingProductLists(id)?
-
错误非常简单。 Entity Framework 具有您从数据库中检索到的实体的缓存。此实体已添加到本地缓存中,因此您无法将非附加实体添加到缓存中,因为缓存中已存在另一个版本(很可能来自数据库)。
标签: c# asp.net-mvc entity-framework entity-framework-5