TryGetObjectStateEntry返回false,但是当我尝试附加实体时,我得到'ObjectStateManager中已存在具有相同键的对象。 ObjectStateManager无法使用相同的键跟踪多个对象。'
实体键的类型为Guid。
这怎么可能?
编辑:我正在使用不同的密钥附加2个实体。错误始终发生在我附加的此类型的第二个实体上。如果我交换它们,错误仍然在第二个。
public bool IsAttached<T>(T obj) where T : class
{
ObjectStateEntry entry = null;
ObjectContext objCtx = GetObjectContext();
bool isKeyAttached = false;
EntityContainer container = objCtx.MetadataWorkspace.GetEntityContainer(objCtx.DefaultContainerName, DataSpace.CSpace);
EntitySetBase entitySet = container.BaseEntitySets.Where(item => item.ElementType.Name.Equals(typeof(T).Name)).FirstOrDefault();
System.Data.EntityKey key = objCtx.CreateEntityKey(entitySet.Name, obj);
if (objCtx.ObjectStateManager.TryGetObjectStateEntry(key, out entry))
{
isKeyAttached = entry.State != System.Data.EntityState.Detached;
}
return isKeyAttached;
}
答案 0 :(得分:1)
如果您附加的实体具有引用其他实体的导航属性,则可能会出现此问题。例如:
public class Parent
{
public int Id { get; set; }
public Child Child { get; set; }
}
public class Child
{
public int Id { get; set; }
}
以下代码将引发异常:
using (var context = new MyDbContext())
{
var parent = new Parent { Id = 1 };
var child1 = new Child { Id = 1 };
parent.Child = child1;
var child2 = new Child { Id = 1 }; // same key
context.Children.Attach(child2); // child with key = 1 is attached now
var objContext = ((IObjectContextAdapter)context).ObjectContext;
ObjectStateEntry entry;
bool isAttached = objContext.ObjectStateManager.TryGetObjectStateEntry(
new EntityKey("MyDbContext.Parents", "Id", parent.Id), out entry);
// isAttached will be false because a Parent with Id = 1 is not attached
if (!isAttached)
{
// we assume now that we could attach the parent safely
context.Parents.Attach(parent);
// Assumption is wrong -> Exception, because Attach attaches the whole
// object graph, so it tries also to attach child1 together with parent
// But child1 has the same key as child2 which is already attached
}
}
因此,关键是TryGetObjectStateEntry
仅检查基本实体的状态,不考虑任何导航属性。另一方面,Attach
不仅附加了基本实体,还附加了尚未附加的子项,导致例外。
答案 1 :(得分:0)
我在 Entity Framework 6.4.4 中遇到了同样的问题,但问题是我误解了 EntityKey
的 qualifiedEntitySetName
构造函数参数的语法。
在我的例子中,我有一个像这样的 SQL Server 表:
CREATE TABLE dbo.Orders (
TenantId int NOT NULL,
OrderId int NOT NULL,
etc
CONSTRAINT PK_Orders PRIMARY KEY ( TenantId, OrderId )
)
qualifiedEntitySetName
参数必须由两个用点分隔的标签组成,例如Foo.Bar
- 我认为该名称将是完全限定的数据库对象名称(即我认为它是 dbo.Orders
),但实际上第一部分必须是 DbContext
名称。>
这是我的错误代码:
Boolean TryGetOrderFromContext( this ContosoDbContext db, Int32 tenantId, Int32 orderId, out Order order )
{
EntityKey orderKey;
{
KeyValuePair<String,Object>[] orderKeyValues = new[]
{
new KeyValuePair<String,Object>( "TenantId", tenantId ),
new KeyValuePair<String,Object>( "OrderId" , orderId )
};
orderKey = new EntityKey( qualifiedEntitySetName: "dbo.Orders", entityKeyValues: orderKeyValues )
}
ObjectContext objCtx = ((IObjectContextAdapter)db).ObjectContext;
ObjectStateManager objMgr = db.ObjectStateManager;
if( osm.TryGetObjectStateEntry( orderKey, out ObjectStateEntry se ) )
{
order = se.Entity;
if( order is null ) throw new InvalidOperationException( "se.Entity is null." );
return true;
}
order = default;
return false;
}
由于我的 DbContext
被命名为 ContosoDbContext
,因此 EntityKey
构造函数和其余代码应该是这样的:
Boolean TryGetOrderFromContext( this ContosoDbContext db, Int32 tenantId, Int32 orderId, out Order order )
{
EntityKey orderKey;
{
KeyValuePair<String,Object>[] orderKeyValues = new[]
{
new KeyValuePair<String,Object>( "TenantId", tenantId ),
new KeyValuePair<String,Object>( "OrderId" , orderId )
};
orderKey = new EntityKey( qualifiedEntitySetName: "ContosoDbContext.Orders", entityKeyValues: orderKeyValues )
}
// etc
}
...现在 TryGetObjectStateEntry
正确返回 true
!