2009-09-23 95 views
1

这是一个好的或不好的主意?关于存储库模式的问题

public interface IRepository<T> 
{ 
    ... 
    IList<T> Get(Func<T, bool> predicate) 
    ... 
} 

我的意思是 - 它似乎真的很强大的附加功能,我可以实现它太(至少 - 在一定的水平),但我的胆量告诉我,这是一种错误的。任何人都可以启发我吗?

+0

@AdamRalph如果我知道 - 我不会问。这只是一种直觉。 – 2009-09-23 09:53:12

回答

1

那么,它肯定是一个强大的功能。问题是:在界面中引入它会强制IRepository的所有实现提供一个合适的定义 - 根据实现可能不可能(或者至少非常困难)(例如,由数据库连接支持的实现或其他)。

也许,你应该做的,而不是

public interface IRepository<T> 
{ 
    ... 
} 

public interface IAdvancedRepository<T>: IRepository<T> 
{ 
    IList<T> Get(Func<T, bool> predicate) 
} 

,并只提供Get,如果实现能有效地做到这一点。

+0

也想过这个。但我想知道 - 一般来说,提供这种API(通过超泛型谓词查询)是一个好主意。这会导致像'FindByCountryName'和'GetByLastName'这样的储存库方法的必要性消失。基本上 - 我从存储库中移出一个问题来回答质疑我究竟在询问什么。看来我错过了一些东西,这会在未来导致严重的问题。 – 2009-09-23 09:50:04

+2

问题是,您正在使用此解决方案有效地强制执行“全表扫描”,也就是说,即使您的存储库实现在LastName(哈希表,DB索引等)上有索引,您不能在实现Get的过程中使用它,因为您不知道哪些属性会被谓词实际测试。这对“IRespository”的实施施加了严重的限制。 – Dirk 2009-09-23 09:58:21

+0

您不应删除关于索引的那一点。我认为这是一个有效的观点。缺乏明确性会导致更难维护数据库。 – 2009-09-23 09:59:02

3

我觉得这是更好的:

public interface IRepository<T> 
{ 
IQueryable<T> GetAll(); 
} 

,那么你可以写你的自定义查询为:

var employees=Repositroy<Employee>.GetAll().Where(emp=>emp.Salary>10000).Select(emp=>emp).ToList(); 
+1

这是如果我们知道暴露完整的查询API是不错的主意。 – 2009-09-23 10:22:40

0

我倾向于将'Get'链接到一个简单的实例,而不是一个列表。 因此,当我有一个方法返回一个集合时,我通常将该方法命名为“Find”或类似的东西。

(请注意,FxCop会告诉你,使用'Get'作为函数名是个坏主意)。

啊,好的,我错过了这一点。 :) 我不会创建一个方法,它将一个标准作为参数。我宁愿在我的存储库上使用专门的方法,而不是传入各种标准。 我知道,它不是那么灵活,但它更加明确。

+0

这已经接近点。但是它只是为了明确吗? – 2009-09-23 09:57:02

0

对我来说,它似乎并不需要知识库,因为.NET开发人员通常都会理解它。

我想你需要的东西是这样的:

public interface IStore { 
    // Low-level abstraction over a real database 
} 

public interface IAction<TInput, TResult> { // Or maybe ICommand? 
    TResult Execute(TInput input); 
} 

// then: 
public interface IGetCustomerById : IAction<int, Customer> { 
} 
public class GetCustomerById : IGetCustomerById { 
    IStore store; 
    public GetCustomerById(IStore store) { 
     this.store = store; 
    } 

    public Customer Execute(int id) { 
     return store.ResultOfExecutedSqlOrWhatever(id); 
    } 
} 
// it might not only be READ action but more complex one, reusing other actions too 
public class ApproveCustomer<ApprovalInfo,ApprovalResult> : IAction { 
    IStore store; 
    IGetCustomerById getCustomer; 
    public ApproveCustomer(IStore store, IGetCustomerById getCustomer) { 
     this.store = store; 
     this.getCustomer = getCustomer; 
    } 

    public ApprovalResult Execute(ApprovalInfo approval) { 
     var customer = getCustomer.Execute(approval.CustomerId); 
     var result = new ApprovalResult(); 
     if (customer == null) { 
      result.Message = "No such customer"; 
      return result; 
     } 
     if (!customer.IsEligibleForSomething()) { // This can be another action! 
      result.Message = "Not eligible" 
      return result; 
     } 
     result.Message = "Successfully approved" 
     result.IsApproved = true; 
     return result; 
    } 
} 

附加在这里的好处是,所有这些行动可以依赖注入很容易地使用。

+0

缺点是什么? – 2009-09-23 10:18:08

+0

一个缺点是它可能需要更多的代码。 – 2009-09-23 12:10:22