代码之家  ›  专栏  ›  技术社区  ›  CVertex

返回IQueryable<T>或不返回IQueryable<T>

  •  73
  • CVertex  · 技术社区  · 17 年前

    我有一个repository类,它将LINQ包装到SQL数据上下文。repository类是一个包含所有数据层逻辑(和缓存等)的业务线类。

    这是我的回购接口的v1。

    public interface ILocationRepository
    {
        IList<Location> FindAll();
        IList<Location> FindForState(State state);
        IList<Location> FindForPostCode(string postCode);
    }
    

    但是为了处理FindAll的分页,我正在考虑是否公开IQueryable<ILocation>而不是IList,以简化分页等情况下的接口。

    非常感谢您的帮助。

    3 回复  |  直到 17 年前
        1
  •  90
  •   Marc Gravell    17 年前

    赞成者;可组合性:

    • 呼叫者可以添加过滤器
    • 呼叫者可以添加分页

    • 您的存储库不再适合进行单元测试;你不能依赖于a:它能工作,b: 是的;
      • 调用方可以添加不可翻译的函数(即没有TSQL映射;在运行时中断)
      • 调用方可以添加一个过滤器/排序,使其像狗一样运行
    • IQueryable<T> 为了实现可组合性,它排除了不可组合的实现,或者迫使您为它们编写自己的查询提供程序
    • 这意味着您无法优化/配置DAL

    为了稳定,我选择了 Expression<...> 在我的存储库上。这意味着我知道存储库的行为,我的上层可以使用mock,而不用担心“实际存储库是否支持此功能?”(强制集成测试)。

    IQueryable<T> 在…内 more thoughts on this theme here . 在存储库界面上放置分页参数同样容易。您甚至可以使用扩展方法(在接口上)添加 可选择的 分页参数,因此具体类只有1个方法要实现,但调用方可能有2或3个重载可用。

        2
  •  7
  •   Akash Kava    17 年前

    正如前面的回答所提到的,公开IQueryable可以让呼叫者使用IQueryable本身,这是或可能会变得危险。

    封装业务逻辑的首要职责是维护数据库的完整性。

    public interface ILocationRepository
    {
        IList<Location> FindAll(int start, int size);
        IList<Location> FindForState(State state, int start, int size);
        IList<Location> FindForPostCode(string postCode, int start, int size);
    }
    

    如果大小==-1,则返回所有。。。

    另一种方式。。。

    public class MyRepository
    {
        IQueryable<Location> FindAll()
        {
            List<Location> myLocations = ....;
            return myLocations.AsQueryable<Location>;
            // here Query can only be applied on this
            // subset, not directly to the database
        }
    }
    

        3
  •  2
  •   Konstantin Tarkus    17 年前

    我建议使用 IEnumerable 而不是 IList ,你会有更多的灵活性。

    这样,您将能够从数据库中只获取您真正要使用的部分数据,而无需在存储库中进行额外的工作。

    // Repository
    public interface IRepository
    {
        IEnumerable<Location> GetLocations();
    }
    
    // Controller
    public ActionResult Locations(int? page)
    {
        return View(repository.GetLocations().AsPagination(page ?? 1, 10);
    }
    

    这是超级干净和简单。