Should a Repository return IEnumerable , IQueryable or List?

后端 未结 4 1169
星月不相逢
星月不相逢 2020-12-31 02:44

I\'d like to make my application as flexible as possible, but not dig myself into a hole by making my Interface too specific.

What is the best object

4条回答
  •  挽巷
    挽巷 (楼主)
    2020-12-31 03:34

    There is a very good recent article here that covers this, namely under the heading "Repositories that return IQueryable". This is what it says:

    One of the reasons we use the repository pattern is to encapsulate fat queries. These queries make it hard to read, understand and test actions in ASP.NET MVC controllers. Also, as your application grows, the chances of you repeating a fat query in multiple places increases. With the repository pattern, we encapsulate these queries inside repository classes. The result is slimmer, cleaner, more maintainable and easier-to-test actions. Consider this example:

    var orders = context.Orders
        .Include(o => o.Details)
        .ThenInclude(d => d.Product)
        .Where(o => o.CustomerId == 1234);
    

    Here we are directly using a DbContext without the repository pattern. When your repository methods return IQueryable, someone else is going to get that IQueryable and compose a query on top of it. Here’s the result:

    var orders = repository.GetOrders()
        .Include(o => o.Details)
        .ThenInclude(d => d.Product)
        .Where(o => o.CustomerId == 1234);
    

    Can you see the difference between these two code snippets? The only difference is in the first line. In the first example, we use context.Orders, in the second we use repository.GetOrders(). So, what problem is this repository solving? Nothing!

    Your repositories should return domain objects. So, the GetOrders() method should return an IEnumerable. With this, the second example can be re-written as:

    var orders = repository.GetOrders(1234);

    See the difference?

    As a result of this, I've added the following coding convention within my team:

    For repository class methods, never return a IQueryable object. Always enumerate or convert it first (e.g., ToArray, ToList, AsEnumerable).

    The reasoning being that IQueryable would allow the caller to build on this and ultimately modify the SQL query that is executed on the database. This can potentially be dangerous in terms of DB performance, but it is more about SoC. The caller doesn’t care about the data source; it just wants the data.

提交回复
热议问题