是否可以检查一个对象是否已经附加到entity framework中的数据上下文?
尝试附加已经通过context.AttachTo(...)
连接到给定上下文的对象时出现以下错误:
ObjectStateManager中已经存在具有相同键的对象。 ObjectStateManager不能使用同一个键跟踪多个对象。
有没有一种方法可以实现以下几点:
context.IsAttachedTo(...)
干杯!
编辑:
杰森所提出的扩展方法非常接近,但对我的情况并不适用。
我正在尝试使用另一个问题的答案中概述的方法做一些工作:
如何从我的表中删除一行或多行使用Linq的实体*没有*首先检索行?
我的代码看起来有点像这样:
var user = new User() { Id = 1 }; context.AttachTo("Users", user); comment.User = user; context.SaveChanges();
这工作正常,除非我为该用户做其他事情,我使用相同的方法,并尝试附加一个虚拟的User
对象。 这失败了,因为我以前已经附加了这个虚拟用户对象。 我如何检查这个?
这就是我最后的结果,这非常好:
public static void AttachToOrGet<T>(this ObjectContext context, string entitySetName, ref T entity) where T : IEntityWithKey { ObjectStateEntry entry; // Track whether we need to perform an attach bool attach = false; if ( context.ObjectStateManager.TryGetObjectStateEntry ( context.CreateEntityKey(entitySetName, entity), out entry ) ) { // Re-attach if necessary attach = entry.State == EntityState.Detached; // Get the discovered entity to the ref entity = (T)entry.Entity; } else { // Attach for the first time attach = true; } if (attach) context.AttachTo(entitySetName, entity); }
你可以这样调用它:
User user = new User() { Id = 1 }; II.AttachToOrGet<Users>("Users", ref user);
这工作非常好,因为它就像context.AttachTo(...)
除了你可以使用我每次上面引用的ID技巧。 您最终会得到以前连接的对象或您自己的对象被连接。 在上下文中调用CreateEntityKey
可以确保它是很好的和通用的,并且即使对于没有进一步编码的复合键也能工作(因为EF已经可以为我们做这个了!)。
一个更简单的方法是:
bool isDetached = context.Entry(user).State == EntityState.Detached; if (isDetached) context.Users.Attach(user);
试试这个扩展方法(这是未经testing的和非常规的):
public static bool IsAttachedTo(this ObjectContext context, object entity) { if(entity == null) { throw new ArgumentNullException("entity"); } ObjectStateEntry entry; if(context.ObjectStateManager.TryGetObjectStateEntry(entity, out entry)) { return (entry.State != EntityState.Detached); } return false; }
鉴于您在编辑中描述的情况,您可能需要使用以下接受EntityKey
而不是对象的重载:
public static bool IsAttachedTo(this ObjectContext, EntityKey key) { if(key == null) { throw new ArgumentNullException("key"); } ObjectStateEntry entry; if(context.ObjectStateManager.TryGetObjectStateEntry(key, out entry)) { return (entry.State != EntityState.Detached); } return false; }
要在您的情况下构build一个EntityKey
,请使用以下内容作为指导:
EntityKey key = new EntityKey("MyEntities.User", "Id", 1);
您可以通过使用属性User.EntityKey
(从接口IEntityWithKey
)从现有的User
实例中获取EntityKey
。
使用您试图检查的对象的实体键:
var entry = context.ObjectStateManager.GetObjectStateEntry("EntityKey"); if (entry.State == EntityState.Detached) { // Do Something }
善良,
担
这不直接回答OP的问题,但这是我解决我的问题。
这是为那些正在使用DbContext
而不是ObjectContext
。
public TEntity Retrieve(object primaryKey) { return DbSet.Find(primaryKey); }
DbSet.Find方法 :
查找具有给定主键值的实体。 如果具有给定主键值的实体存在于上下文中,则立即返回,而不向商店发出请求。 否则,向商店发出一个请求,要求具有给定主键值的实体,如果find,则将该实体附加到上下文并返回。 如果在上下文或商店中找不到实体,则返回null。
基本上,它返回给定primaryKey
的附加对象,所以你只需要在返回的对象上应用更改以保持正确的实例。