1

我使用MVC 3中的EF4 POCO和UnitOfWork/repository模式。我想了解如何修改要插入的新記錄。如何在EF4中提交之前更新新記錄?

我的服務方法插入/更新看起來像這樣(倉庫在服務構造通過的IoC注入):

public void UpdateData(Guid id, int newValue) 
{ 
    MyPoco poco = _repository.FirstOrDefault(p => p.Id = id); 

    if (poco == null) 
    { 
     poco = new Poco 
     { 
      //set properties 
     }; 

     _repository.Add(poco); 
    } 

    poco.SomeFieldToUpdate = newValue; 
} 

我的變化獲得通過我的UnitOfWork堅持上一個UseUnitOfWorkAttribute行爲過濾我控制器:

void IResultFilter.OnResultExecuted(ResultExecutedContext filterContext) 
{ 
    var unitOfWork = IoCFactory.Instance.CurrentContainer.Resolve<IUnitOfWork>(); 
    unitOfWork.Commit(); 
} 

當然,如果這是有史以來打只有一次,對於現有的或新的數據能正常工作。如果它已經存在,它可以在多次通行證中正常工作。

但是,如果Guid值不存在於表中,那麼它會嘗試執行多次插入(如果多次調用)。

所以這是我的困境。我明白爲什麼這不起作用,我只是不確定解決問題的正確方法。基本上,我需要以某種方式獲得對UnitOfWork中現有POCO的引用,並以某種方式更新它。但UnitOfWork在我的服務中沒有(按設計) - 我甚至不知道如何將實體拉出UoW並進行更新。

我在談論這個錯誤還是我忽略了一些簡單的東西?或者我在設計這個方面存在根本性缺陷?我有一種感覺,我可能會比應該做得更難。

在此先感謝。

+0

你在哪裏插入新的Poco到版本庫中以及何時/何地調用SaveChanges?你在上面的代碼中創建的Poco直接進入垃圾收集,對象沒有任何反應。我認爲有一些重要的代碼片段不能理解問題。你能多加一點嗎? – Slauma 2011-03-19 13:02:48

+0

是的,這只是我的一個疏忽(已經很晚了)。 :)它已被添加。 – 2011-03-19 14:46:48

回答

2

發生這種情況的原因是因爲您的實體尚未保存,您執行查詢來獲取它。查詢將無法在數據庫中找到它並正確返回null。

您應該不需要使用存儲庫/工作單元/ ObjectContex作爲服務調用中未保存的實體的內部存儲。如果你需要它,你應該檢查你的應用程序設計並重構它,因爲可能有錯誤。

無論如何,你可以從上下文中得到沒有保存的實體,但它不是很好的代碼。您需要使用特殊的方法才能通過標識獲取實體。您將使用它而不是調用FirstOrDefault。喜歡的東西:

public MyPoco GetById(Guid id) 
{ 
    MyPoco enity = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added) 
     .Where(e => e.Entity != null && e.Entity.GetType() == typeof(MyPoco))) 
     .Select(e => (MyPoco)e.Entity) 
     .Where(p => p.Id == id) 
     .SingleOrDefault(); 

    if (entity == null) 
    { 
     entity = context.MyPocos.FirstOrDefault(p => p.Id == id); 
    } 
} 
+0

感謝您的幫助。所以在我的設計中,我主要將這個問題用於存儲在我的數據庫中的自定義會話數據,並且我試圖在各個位置採取各種操作(登錄,註銷,登錄操作過濾器),而這些操作是分散的在我的應用程序。我的問題是這些都是鬆散耦合的,所以我沒有簡單的方法來保持示波器連接。有什麼建議麼? – 2011-03-19 16:54:37

+0

根據您對「您不應該需要使用存儲庫/工作單元/ ObjectContex作爲服務調用中未保存的實體的內部存儲」的評論,我深入瞭解了我的設計,並決定將我的Session poco保留在我的自定義UserPrincipal。這不僅給了我交叉訪問權限,而且它似乎也屬於這裏。感謝您挑戰我的設計。 – 2011-03-21 06:07:49

0

你設置你進入UpdateData作爲新的波蘇對象的關鍵,像這樣的ID:

poco = new Poco 
{ 
    Id = id; 
    //set properties 
}; 

如果是的話,你可以爲對象查詢不FirstOrDefault但通過在儲存庫方法使用TryGetObjectByKey

public Poco GetPocoByKey(Guid id) 
{ 
    EntityKey key = new EntityKey("MyEntities.Pocos", "Id", id); 
    object pocoObject; 
    if (context.TryGetObjectByKey(key, out pocoObject)) 
     return (Poco)pocoObject; 

    return null; 
} 

的優點是,TryGetObjectByKey着眼於先入ObjectConte xt如果它可以找到具有指定鍵的對象。只有沒有,那麼數據庫將被查詢。由於第一次找不到新的Poco時,TryGetObjectByKey應該在上下文中再次搜索具有相同鍵的對象時找到它,即使它尚未保存到數據庫中。

編輯:此解決方案不起作用!

由於TryGetObjectByKey沒有找到針對其在added狀態在ObjectContext的對象鍵,即使不如果鍵不是DB生成的密鑰和由應用程序提供(見下文評論)。

+0

我擔心這不會與未保存的實體一起工作,因爲它具有臨時密鑰。 – 2011-03-19 15:50:36

+0

啊,我明白了。對於不在數據庫中自動生成的身份也是這種情況嗎?這正是我想到的,因爲poco似乎有一個「Guid」作爲鍵(通常不是DB創建的,而是在應用程序中生成的)。 EF不使用此密鑰作爲最終的非臨時密鑰,因爲它知道在數據庫中不會分配另一個密鑰? – Slauma 2011-03-19 15:59:53

+0

我只是試圖調用GetObjectByKey爲新的實體添加到上下文(但沒有保存),我得到了一個異常,所以可能沒有,但也許我做錯了什麼。 – 2011-03-19 16:04:07

相關問題