If I expose IQueryable from my service layer, woul

2020-06-25 19:12发布

问题:

If I expose IQueryable from my service layer, wouldn't the database calls be less if I need to grab information from multiple services?

For example, I'd like to display 2 separate lists on a page, Posts and Users. I have 2 separate services that provides a list of these. If both provides IQueryable, will they be joint in 1 database call? Each repository creates a context for itself.

回答1:

It's best to think of an IQueryable<T> as a single query waiting to be run. So if you return 2 IQueryable<T> instances and run them in the controller, it wouldn't be any different than running them separably in their own service methods. Each time you execute the IQuerable<T> to get results, it will run the query by itself independent of other IQuerable<T> objects.

The only time (as far as I know) it will make an impact if there is enough time between the two service calls that the database connection might close, but you would need a considerable amount of time in between the service calls for that to be the case.

Returning IQuerable<T> to the controller still has some usefulness, such as easier handling of paging and sorting (so sorting is done on the controller and is not done on the service layer which doesn't necessarily care about how data is sorted or paged). This isn't a performance concern though, and people will disagree about if it's best to do this in the controller or not (I've seen reputable developers do this and give well thought out reasons why).



回答2:

No. The best an IQueryable can do is reduce the number of calls within a singular database context. An IQueryable will not cross contexts.

Personally, I don't use IQueryables past the repositories for a number of reasons:

1) I don't use the same domain objects as database objects, and seeing "no translation to SQL" pisses me off ;)

2) I don't like the necessary structure for IQueryables in views: foreach (var item in collection){var tempItem = item; code on tempItem}

3) I've come up with a method of passing generic filters to the data layer (LinqKit and PredicateBuilder are gods)

If these reasons don't apply to you, of course you should feel free to use IQueryables to whichever layer you desire.



回答3:

Not with two different contexts.



回答4:

Definitely NO. It's a leaky abstraction.

It allows abominations like this:

q.Where(x=>{Console.WriteLine("fail");return true;});

Thing is - when exposing IQueryable, You are saying that Your data layer fully supports linq to objects.



回答5:

If you make two method calls you will make two queries.

You can combine the methods into a single method which gets all the data at once. If you are implementing the repository pattern you will have an easier time if you instantiate one database context per request.



回答6:

Your service layer is exactly that, a layer which serves up what you need. Often times my service layers are named things like SearchService which has methods for returning every packaged collection I will ever need (the actual view models themselves). And if I ever need a new search, my service layer gets a new method. The backing for your service layer can then contain any data backing or persistence model you would like, be it a repository or Entity Framework provider, etc.

To answer your question though, the line needs to be drawn at the service layer, all queries need to be contained within it and only data returned.