2014-09-19 54 views
0

我試圖更新使用實體框架版本6.無法更新實體使用EF 6 - ObjectStateManager錯誤

我是從像這樣的數據庫選擇實體的實體...

public T Find<T>(object id) where T : class 
    { 
     return this._dbContext.Set<T>().Find(id); 
    } 

和更新,像這樣的實體..

public T Update<T>(T entity) where T : class 
    { 
     // get the primary key of the entity 
     object id = this.GetPrimaryKeyValue(entity); 

     // get the original entry 
     T original = this._dbContext.Set<T>().Find(id); 


     if (original != null) 
     { 
      // do some automatic stuff here (taken out for example) 

      // overwrite original property values with new values 
      this._dbContext.Entry(original).CurrentValues.SetValues(entity); 
      this._dbContext.Entry(original).State = EntityState.Modified; 

      // commit changes to database 
      this.Save(); 

      // return entity with new property values 
      return entity; 
     } 

     return default(T); 
    } 

的GetPrimaryKeyValue功能是如此...

private object GetPrimaryKeyValue<T>(T entity) where T : class 
    { 
     var objectStateEntry = ((IObjectContextAdapter)this._dbContext).ObjectContext 
      .ObjectStateManager 
      .GetObjectStateEntry(entity); 

     return objectStateEntry.EntityKey.EntityKeyValues[0].Value; 
    } 

只是爲了清晰。我正在選擇原始條目,因爲我需要執行一些併發邏輯(我已經取出)。我不會將這些數據發佈到實體,並且需要再次手動從數據庫中選擇它以執行檢查。

我知道如果實體上有多個主鍵,GetPrimaryKeyValue函數並不理想。我只是想讓它現在工作。

更新時,實體框架在嘗試執行GetPrimaryKeyValue函數時咳嗽下面的錯誤。

的ObjectStateManager不包含ObjectStateEntry一起類型的對象的引用「NAME_OF_ENTITY_IT_CANNOT_FIND」

我之前寫了很多庫,我從來沒有過這樣的問題,我似乎無法找到原因它不工作(因此後)。

任何幫助將不勝感激。

謝謝你們!

史蒂夫

+0

我有點被你的代碼混淆。您的變更跟蹤器中是否有T實體?因爲如果是這樣,那麼調用_dbContext.Set ().Find(id)不會進行數據庫查詢。它會查看變更跟蹤器,看它是否已經存在(它會是),然後給你同一個實體。所以原創和實體在這一點上是相同的參考。 – Dismissile 2014-09-19 12:34:15

+0

與上面的註釋相關,如果T實體在更改跟蹤器中被傳遞到Update方法中,那麼您不能調用CurrentValues()。 – Dismissile 2014-09-19 12:36:32

+0

嗨Dismissile。即使我拿出所有的代碼,然後留在'this._dbContext.Entry(ENTITY).State = EntityState.Modified;'。我仍然得到錯誤。'一個實體對象不能被IEntityChangeTracker的多個實例引用。'這是否意味着它已經是變更追蹤器的一部分? – Hemslingo 2014-09-19 12:43:35

回答

0

好像您在傳遞中充分利用實體PK的問題。而不是試圖去通過EF得到這個數據,您既可以使用他們的關鍵屬性,或者創建自己的,只是使用反射來收集關鍵名稱。如果需要的話,這也將允許您檢索多個密鑰。下面是我在LinqPad內部創建的一個示例,您應該能夠將其設置爲「程序」模式,並將其粘貼並看到它的工作。破解代碼並使用你的可能。我實現了一個IEntity,但它並不是必需的,您可以將屬性更改爲任何真正的屬性。

下面是結果:

Keys found: 
CustomIdentifier 
LookASecondKey 

下面是代碼:

// this is just a usage demo 
void Main() 
{ 
    // create your object from wherever 
    var car = new Car(){ CustomIdentifier= 1, LookASecondKey="SecretKey", Doors=4, Make="Nissan", Model="Altima" }; 

    // pass the object in 
    var keys = GetPrimaryKeys<Car>(car); 

    // you have the list of keys now so work with them however 
    Console.WriteLine("Keys found: "); 
    foreach(var k in keys) 
      Console.WriteLine(k); 
} 

// you probably want to use this method, add whatever custom logic or checking you want, maybe put 
private IEnumerable<string> GetPrimaryKeys<T>(T entity) where T : class, IEntity 
{ 
    // place to store keys 
    var keys = new List<string>(); 

    // loop through each propery on the entity 
    foreach(var prop in typeof(T).GetProperties()) 
    { 
     // check for the custom attribute you created, replace "EntityKey" with your own 
     if(prop.CustomAttributes.Any(p => p.AttributeType.Equals(typeof(EntityKey)))) 
      keys.Add(prop.Name); 
    } 

    // check for key and throw if not found (up to you) 
    if(!keys.Any()) 
     throw new Exception("No EntityKey attribute was found, please make sure the entity includes this attribute on at least on property."); 

    // return all the keys 
    return keys; 
} 

// example of the custom attribute you could use 
[AttributeUsage(AttributeTargets.Property)] 
public class EntityKey : Attribute 
{ 

} 

// this interface is not NEEDED but I like to restrict dal to interface 
public interface IEntity { } 

// example of your model 
public class Car : IEntity 
{ 
    [EntityKey] // add the attribure to property 
    public int CustomIdentifier {get;set;} 

    [EntityKey] // i am demonstrating multiple keys but you can have just one 
    public string LookASecondKey {get;set;} 

    public int Doors {get;set;} 
    public string Make {get;set;} 
    public string Model {get;set;} 
} 
+0

嗨,託尼。感謝您的快速回復。我試過這個,我得到以下錯誤。 '一個實體對象不能被IEntityChangeTracker的多個實例引用。'所以這告訴我,它已經附加到上下文權限?!? – Hemslingo 2014-09-19 12:34:12

+0

是的,實體是有效的,但是當調用SaveChanges()時它不會報錯,但也不會更新數據庫。 – Hemslingo 2014-09-19 12:44:52

+0

道歉,糾正上述評論我甚至沒有得到原來的爆炸時,我試圖從已發佈的實體(這應該是上下文的一部分)抓住主鍵值 – Hemslingo 2014-09-19 12:48:23