返回 IQueryable或不返回 IQueryable

发布于 2024-07-15 22:36:30 字数 1431 浏览 8 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

残花月 2024-07-22 22:36:31

正如前面的答案所提到的,公开 IQueryable 可以让调用者访问 IQueryable 本身,这是危险的,或者可能会变得危险。

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

您可以继续公开 IList,并可以按如下方式更改您的参数,这就是我们正在做的...

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);
}

如果 size == -1 则返回所有...

替代方式...

如果您仍然这样做想要返回 IQueryable,那么您可以在函数内返回 IQueryable 的 List。例如...

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
    }
}

第一个方法比内存有优势,因为您将返回更少的数据而不是全部。

As mentioned by previous answer, exposing IQueryable gives access to callers to play with IQueryable itself, which is or it can become dangerous.

Encapsulating business logic's first responsibility is to maintain integrity of your database.

You can continue exposing IList and may be change your parameters as following, this is how we are doing...

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);
}

if size == -1 then return all...

Alternative way...

If you still want to return IQueryable, then you can return IQueryable of List inside your functions.. for example...

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
    }
}

First method has an advantage over memory, because you will return less data instead of all.

十级心震 2024-07-22 22:36:31

我建议使用 IEnumerable 而不是 IList,使用它您将拥有更大的灵活性。

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

示例:

// Repository
public interface IRepository
{
    IEnumerable<Location> GetLocations();
}

// Controller
public ActionResult Locations(int? page)
{
    return View(repository.GetLocations().AsPagination(page ?? 1, 10);
}

超级干净简单。

I recommend using IEnumerable instead of IList, with it you will have more flexibility.

This way you will be able to get from Db only that portion of data which you really gonna use without extra work done in your repository.

Sample:

// Repository
public interface IRepository
{
    IEnumerable<Location> GetLocations();
}

// Controller
public ActionResult Locations(int? page)
{
    return View(repository.GetLocations().AsPagination(page ?? 1, 10);
}

Which is super clean and simple.

你对谁都笑 2024-07-22 22:36:30

优点; 可组合性:

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

缺点; 不可测试性:

  • 您的存储库不再可以进行适当的单元测试; 你不能依赖a:它有效,b:它做什么;
    • 调用者可以添加不可翻译的函数(即无 TSQL 映射;在运行时中断)
    • 调用者可以添加一个过滤器/排序,使其像狗一样执行
  • 因为调用者期望 IQueryableIQueryable是可组合的,它排除了不可组合的实现 - 或者它迫使您为它们编写自己的查询提供程序,
  • 这意味着您无法优化/分析 DAL

为了稳定性,我采取了不< /strong> 在我的存储库上公开 IQueryableExpression<...>。 这意味着我知道存储库的行为方式,并且我的上层可以使用模拟,而不必担心“实际存储库支持这个吗?” (强制集成测试)。

我仍然在存储库内部使用 IQueryable 等 - 但不会超出边界。 我在此发布了一些关于此主题的更多想法。 在存储库界面上放置分页参数也同样容易。 您甚至可以使用扩展方法(在接口上)添加可选分页参数,以便具体类只有 1 个方法要实现,但可能有 2 或 3 个重载可供调用者使用。

The pros; composability:

  • callers can add filters
  • callers can add paging
  • callers can add sorting
  • etc

The cons; non-testability:

  • Your repository is no longer properly unit testable; you can't rely on a: it working, b: what it does;
    • the caller could add a non-translatable function (i.e. no TSQL mapping; breaks at runtime)
    • the caller could add a filter/sort that makes it perform like a dog
  • Since callers expect IQueryable<T> to be composable, it rules out non-composable implementations - or it forces you to write your own query provider for them
  • it means you can't optimize / profile the DAL

For stability, I've taken to not exposing IQueryable<T> or Expression<...> on my repositories. This means I know how the repository behaves, and my upper layers can use mocks without worrying "does the actual repository support this?" (forcing integration tests).

I still use IQueryable<T> etc inside the repository - but not over the boundary. I posted some more thoughts on this theme here. It is just as easy to put paging parameters on the repository interface. You can even use extension methods (on the interface) to add optional paging parameters, so that the concrete classes only have 1 method to implement, but there may be 2 or 3 overloads available to the caller.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文