2010-11-28 150 views
2

我正在將一些公共存儲庫基礎結構合併到某些包裝EF,L2SQL和WCF數據服務的應用程序中(儘管基礎數據訪問實現應該是任意的)。我已經對此事進行了一些閱讀,但似乎無法找到真正滿足的例子。通用存儲庫

我開始:

public interface IRepository : IDisposable 
{ 
    IQueryable<T> Query<T>(); 
    void Attach(object entity); 
    void ForDeletion(object entity); 
    void SaveChanges(); 
} 

但我喜歡用窄合同(http://codebetter.com/blogs/gregyoung/archive/2009/01/16/ddd-the-generic-repository.aspx)存儲庫的想法。以上內容讓消費者知道存儲庫支持的所有實體類型。

我不會說這是不可能的,但我很難確信IQueryables本身不應該是存儲庫合同的一部分。我不是鍋爐板代碼的粉絲,我堅信你擁有的越多,引入的維護黑洞就越多。所以,我要說的是,這將是很難說服我,任何看起來像:

Public IEnumerable<Customer> GetCustomersWithFirstNameOf(string _Name) { 
    internalGenericRepository.FetchByQueryObject(new CustomerFirstNameOfQuery(_Name)); //could be hql or whatever 
} 

是什麼,但一個完全糟糕想法。當你想要搜索名字姓氏時怎麼辦?或者名字姓氏等等。您最終將擁有一個擁有超過1000個操作的存儲庫,其中一半重複相同的邏輯。注:我不是調用代碼應該是負責應用的所有過濾和這樣的,而是具有互補的規範源對我來說很有意義:

public static class CustomerSpecifications 
{ 
    public IQueryable<Customer> WithActiveSubscriptions(this IQueryable<Customer> customers, DateTime? start, DateTime? end) 
    { 
     // expression manipulation 
     return customers; 
    } 
} 


// bind some data source 
repository.GetQueryable().WithActiveSubscriptions(); 

好了,往前走,我認爲有域模型明確倉庫聽起來像一個好主意,按以下格式:

public interface IRepository : IDisposable 
{ 
    void SaveChanges(); 
} 

public interface IRepository<T>: IRepository 
{ 
    IQueryable<T> GetQueryable(); 
    void Attach(T entity); 
    void ForDeletion(T entity); 
} 

然後

public class CustomerRepository:IRepository<Customer> 
{ 
    private ObjectContext _context; 
    // trivial implementation 
} 

,但我的這個問題是,它只是讓我DELET e客戶。那麼我想刪除客戶地址的情況呢?也就是說,我使用存儲庫來查詢客戶實體,但是然後想要刪除myCustomer.CustomerAddresses [0]?我需要創建第二個存儲庫來簡單地附加和刪除我想要的地址?

我想我可以有我的CustomerRepository是:

public class CustomerRepository:IRepository<Customer>, IRepository<CustomerAddress> 
{ 
    private ObjectContext _context; 
    // trivial implementation 
} 

這將讓我重新使用存儲庫中刪除CustomerAddresses,但我不知道我的感覺如何繼承IRepository<T>對於圖形的每一個部分我想要公開刪除...

public class CustomerRepository:IRepository<Customer>, IRepository<CustomerAddress> /* this list may get pretty long, and then I really just have a masked EF ObjectContext, don't I? */ 
{ 

任何人都有更好的實施建議嗎?

回答

2

在那裏有很多問題,其中一些答案可能是主觀的/被挑選出來的,但我會隨着拳擊而滾動。

IQueryable vs特定的方法。

我其實同意你的看法。我不喜歡有很多很多方法來定義我的存儲庫上的所有不同操作。我更喜歡允許調用代碼提供規範。現在,我的調用代碼不是我的演示文稿 - 它是一個域服務/ BLL。因此,我們並沒有爲UI充分發揮作用,而只是讓我們的存儲庫保持非常通用。 DDD純粹主義者認爲,存儲庫是您的域模型的抽象,因此應該服務於特定的域操作。我會留下來讓你決定。此外,如果您使用IQueryable,那麼您將強制使用「未知」LINQ提供程序。對我來說不是一個問題,因爲我總是會使用LINQ(例如Entity Framework)的東西。但這是DDD純化論者所面臨的另一個問題。

,我用Expression<Func<T,bool>>我的域名服務,當你要在姓和名

那麼搜索什麼,所以我能做到這一點:

var customers = repository.FindAll<Customer>(x => x.FirstName == "Bob" && x.LastName == "Saget"); 

如果您不喜歡,你可以使用規範模式來使用AND/OR類型的代碼。

刪除客戶地址

那麼一般來說,你應該有每個聚合根一個存儲庫。在不知道域模型的情況下,它聽起來像「客戶」是一個聚合根,「CustomerAddress」是一個總是與「客戶」關聯的聚合(例如不存在沒有合適的客戶)。

因此,您不需要CustomerAddressRepository。 CustomerAddress操作應通過您的CustomerAddress存儲庫完成。

這就是爲什麼我喜歡營造一種GenericRepository<T>實施IRepository<T>其對總(查找,添加,刪除),然後更具體實現從GenericRepository<T>派生實現核心業務。

下面是我將如何處理客戶信息庫。創建一個GenericRepository<T>,它執行IRepository<T>核心操作。然後爲ICustomerRepository創建另一個接口,該接口也實現IRepository<T>

現在,創建一個名爲CustomerRepository的實現,它繼承GenericRepository<T>的核心存儲庫實現,並且還擴展了這個實現以允許額外的操作(如刪除地址)。

public class CustomerRepository : GenericRepository<Customer>, ICustomerRepository 
{ 
    // inherits, for example: 
    // IQueryable<Customer> Query<Customer>(); 

    public void Remove(Address address) 
    { 
     // get the customer (if you havent already got it) 
     var cust = ctx.Customers.SingleOrDefault(x => x.CustId == address.CustId); 
     cust.Addresses.Remove(address); 
    } 
} 

和你ICustomerRepository應該是這樣的:

public interface ICustomerRepository : GenericRepository<Customer>, IRepository<Customer> 
{ 
    // inherited from GenericRepository<Customer> 
    //IQueryable<T> Query<T>(); 
    //void Attach(object entity); 
    //void ForDeletion(object entity); 
    //void SaveChanges(); 
    void Remove(Address address); 
} 

明白我的意思?從真正通用的存儲庫開始,然後根據需要獲取更具體的信息。

您不需要CustomerAddressRepository。如上所示,通過CustomerRepository執行操作。

HTH。

+0

因此,您對每個聚合根擁有GenericRepository ...因爲在CustomerAddress中沒有GenericRepository? – Jeff 2010-11-29 00:52:29