从下面的代码中可以看出,我使用AsNoTracking来获取我的对象。 然后,我甚至使用ObjectSateManager来查看正在发生的事情,我可以看到 在l *系列中没有被跟踪,但我仍然得到了
“ObjectStateManager中已存在具有相同键的对象.ObjectStateManager无法使用相同的键跟踪多个对象”。
有什么想法吗?
==========================================
BasketRepository repo = new BasketRepository();
var ba = repo.GetById(8);
var bpro = new BasketProduct(ba, ba.BasketProducts.First().Product, 3);
repo.AddToBasket(bpro);
repo.Save();
==================================
public Basket GetById(int basketId)
{
// eager-load product info
var basket = dbContext.Baskets.Include("BasketProducts")
.Include("BasketProducts.Product.Brand").AsNoTracking().SingleOrDefault(b => b.BasketId == basketId);;
return basket;
}
======================================
public void AddToBasket(BasketProduct product)
{
var ctx = ((IObjectContextAdapter)dbContext).ObjectContext;
ObjectStateManager objectStateManager = ctx.ObjectStateManager;
var l1 = objectStateManager.GetObjectStateEntries(EntityState.Added);
var l2 = objectStateManager.GetObjectStateEntries(EntityState.Modified);
var l3 = objectStateManager.GetObjectStateEntries(EntityState.Deleted);
//var l4 = objectStateManager.GetObjectStateEntries(EntityState.Detached);
var l5 = objectStateManager.GetObjectStateEntries(EntityState.Unchanged);
var existingProductInBasket = dbContext.BasketProducts.AsNoTracking().SingleOrDefault(b => b.BasketId == product.BasketId && b.ProductId == product.ProductId);
var l6 = objectStateManager.GetObjectStateEntries(EntityState.Added);
var l7 = objectStateManager.GetObjectStateEntries(EntityState.Modified);
var l8 = objectStateManager.GetObjectStateEntries(EntityState.Deleted);
//var l4 = objectStateManager.GetObjectStateEntries(EntityState.Detached);
var l9 = objectStateManager.GetObjectStateEntries(EntityState.Unchanged);
//objectStateManager.
dbContext.Entry<BasketProduct>(product).State = existingProductInBasket == null ? EntityState.Added : EntityState.Modified;
}
答案 0 :(得分:1)
当您使用asNoTracking()时,您将获得一个无法使用EntityState.Modified正常更新的未连接实体。然后,一个技巧是用非缓存的实体值替换缓存的实体值。
这是我用于特殊情况的源代码,其中asNoTracking是必需的。它可以是
private T ReplaceEntity(T cachedEntity, T nonCachedEntity) {
dbContext.Entry(cachedEntity).CurrentValues.SetValues(nonCachedEntity);
return cachedEntity;
}
常见用途可以是:
public virtual T FindFirstBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate, bool asNoTracking = false)
{
if (asNoTracking)
{
T cachedEntity = dbContext.Set<T>().FirstOrDefault(predicate);
T nonCachedEntity = dbContext.Set<T>().AsNoTracking().FirstOrDefault(predicate);
return ReplaceEntity(cachedEntity, nonCachedEntity);
}
return dbContext.Set<T>().FirstOrDefault(predicate);
}
根据您的情况:
var cachedEntity = dbContext.BasketProducts.SingleOrDefault(b => b.BasketId == product.BasketId && b.ProductId == product.ProductId);
var nonCachedEntity = dbContext.BasketProducts.AsNoTracking().SingleOrDefault(b => b.BasketId == product.BasketId && b.ProductId == product.ProductId);
var product= ReplaceEntity(cachedEntity, nonCachedEntity);
dbContext.Entry<BasketProduct>(product).State = EntityState.Modified;
希望它有所帮助!!
答案 1 :(得分:0)
实际上这很糟糕。从概念上讲,习惯这个想法可能有点困难 如何通过EF附加和跟踪事物。秘诀是要记住,如果你有一个对象 图形(与其他对象有关系的对象)每当图形的一个对象附加状态X时,图形中的所有其他对象似乎也都附着在该状态中。
在我的场景中,我非常愚蠢地使用 var bpro = new BasketProduct(ba,ba.BasketProducts.First()。Product,3); 创建一个实际上已存在于数据库中的测试产品,它是该对象的一部分 包含篮子及其产品的图表。当我试图附加这个“新”篮子时,EF正确地抱怨说附图中已经存在一个具有相同键的对象!