2013-08-17 26 views
3

我創建了一個通用的存儲庫類,所有其他存儲庫類都從中繼承而來。這太好了,因爲這意味着幾乎所有的管道工作都是針對所有的倉庫完成的。我把我在談論here,但這裏什麼是我的GenericRepository代碼的完整解釋(有些代碼爲簡潔,刪除):使用實體框架的非常通用的CreateOrUpdate方法

public abstract class GenericRepository<T> : IGenericRepository<T> where T : class, new() 
{ 
    private IMyDbContext _myDbContext; 

    public GenericRepository(IMyDbContext myDbContext) 
    { 
     _myDbContext = myDbContext; 
    } 

    protected IMyDbContext Context 
    { 
     get 
     { 
      return _myDbContext; 
     } 
    } 

    public IQueryable<T> AsQueryable() 
    { 
     IQueryable<T> query = Context.Set<T>(); 
     return query; 
    } 

    public virtual void Create(T entity) 
    { 
     Context.Set<T>().Add(entity); 
    } 

    public virtual void Update(T entity) 
    { 
     Context.Entry(entity).State = System.Data.EntityState.Modified; 
    } 
} 

正如你看到的,我有一個創建方法和更新方法。有一個「CreateOrUpdate」方法會非常方便,所以我不必每次都必須手動檢查現有對象,以便將某些內容保存到數據庫中。

Entity Framework中的每個對象都有一個「Id」,但這裏面臨的挑戰是GenericRepository與「T」一起工作。

現在,有了相當長的介紹,我的具體問題。

如何爲我的GenericRepository創建通用CreateOrUpdate方法?

UPDATE

Marcins響應後,我實現了我的GenericRepository下面的一般方法。我需要一段時間才能測試它是否按預期工作,但它看起來很有希望。

public virtual bool Exists(Guid id) 
{ 
    return Context.Set<T>().Any(t => t.Id == id); 
} 

public virtual void CreateOrUpdate(T entity) 
{ 
    if (Exists(entity.Id)) 
    { 
     var oldEntity = GetSingle(entity.Id); 
     Context.Entry(oldEntity).CurrentValues.SetValues(entity); 
     Update(oldEntity); 
    } 
    else 
    { 
     Create(entity); 
    } 
} 

上面的代碼在更新時有不少於3往返數據庫。我相信它可以被優化,但這不是真正的這個問題的練習。

這個問題處理該主題更好: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key

+1

您將訪問數據庫以確定是否需要插入或更新實體。您只需檢查實體的Id是否爲Guid的默認值。 ('entity.ID == default(Guid)')。如果您打算使用延遲加載,您也可能希望確保始終創建代理。看到這個例子:http://stackoverflow.com/a/16811976/150342 – Colin

+0

一些業務邏輯可能希望在創建時儘早設置一個Guid作爲主鍵,所以我將不得不在數據庫中做一些小的往返處理。否則就是非常好的一點,這在大多數其他情況下都是相關的。謝謝。 –

+0

實際上,每當我嘗試更新時,我的實現失敗,出現以下錯誤:ObjectStateManager中已存在具有相同鍵的對象。 ObjectStateManager不能使用相同的密鑰來跟蹤多個對象。它發生在與現有對象具有相同Guid的新對象時。這與這個問題無關,但只是想讓我知道如果有人想使用這個代碼。 –

回答

4

Id屬性創建一個接口,實現它在每一個你的實體,並添加另一個通用的限制到類:

public interface IEntity 
{ 
    int Id { get; set;} 
} 

而且

public abstract class GenericRepository<T> : IGenericRepository<T> where T : class, IEntity, new() 

因此,您可以使用Id屬性您的通用存儲庫類。

當然 - Id不一定是int,它也可以是Guid

+0

好主意,我會試試看。順便說一下,'class'需要在'IEntity'之前。 –

+0

@NielsBrinch好地方! MSDN並沒有對此說一句話,但你是對的:'struct'或'class'約束必須在列表中第一位。我編輯了我的問題。 – MarcinJuraszek

+0

這很奇妙。我喜歡它。 –