views:

406

answers:

3

Hey everyone,

I am working on a project using ASP.NET MVC, and repository model. I have repository classes, and services which consume these repository classes. My question is: Is it correct to return a IQueryable from my repository class and then use ".Where" and ".OrderBy" in a Service to generate a List? If yes, is it the best practice?

Thanks!

A: 

I don't see why that would be an issue. If you're going to become more specific in the data you will be retrieving in your service layer, that means less data being transferred between the application and the database - which means higher efficiency. Doing so means you will also be implementing lazy loading, or getting the data when you absolutely need it. Considering the statelessness of the web, this is a good thing. You don't want to be retrieving all the data in case you might use it.

In other words, there's no sense in getting the entire list of users, to simply select the one who's name is "Jackolantern."

The best way to think of it is like so -- if you decide to switch from MSSQL to MySQL tomorrow, will you have to replicate business logic? If so, then you're utilizing your repository incorrectly.

MunkiPhD
A: 

Yes, I'm pretty happy with the repository returning IQueryable, but with one caveat: a few Linq functions aren't available across all providers. For example, the Single / SingleOrDefault methods aren't available in Linq to Entities. So your service layer may have to jump through some hoops depending on which concrete implementation of your repository is used.

I usually put the interface of the repository classes in the domain layer and the actual implementations in the service layer.

JasonTrue
+2  A: 

For starters: there's no "right" or "wrong" here. It's just a matter of what works best for you and the system you are building. For example, Rob Conery did an ASP.NET sample application called Storefront with exactly the pattern you're describing and it ignited a big flame war. A large part of the discussion evolved around the Repository pattern that is considered the "original one" as described by Eric Evans in his book Domain Driven Design and that describes the interface of a repository as one that accepts and/or returns actual instances (of lists of instances) and not some query interface.

So much for theory. What to choose for your system? The reason I would not directly choose the IQueryable route is that it actually leaks a bit of my persistence strategy to the client layer (being the service layer in this case). Since it primarily makes sense to return an IQueryable if you're retrieving objects from the database using LINQ to [a database access method (like SQL, Entities, ...)]. Only then will .Where or .OrderBy be optimizing your query result. It obviously doesn't make sense if you're using some database access code code that gets a full list which you then expose from the Repository using LINQ to Objects. So in short: you do tie your client layer into the LINQ-based database access strategy you're using.

Being a bit of a purist myself, I would prefer not to surface this tie to LINQ from out of my repository, and I would choose to offer where- and order-by criteria through the parameters of the operations of the repository. I can do all the retrieval optimization in the repository and return a neat clean set of domain objects.

So in the end it comes down to: whatever works best for you is fine.

Pascal Lindelauf
Except for the caveat of specific provider support for some LINQ methods, LINQ to Objects and Linq to XML work fairly well to handle non-DB cases, and most non-MS ORMs are gradually (but certainly not yet completely) supporting LINQ. The OO-purist may not like functional abstractions leaking into their OO model, perhaps, but I don't see a DDD-relevant concern. Retrieving data is usually a domain-specific concern, after all, regardless of the store.
JasonTrue
You touch on a good point Jason: the repository is not always just a layer on top of a database, but can sit on top of any data storage mechanism, e.g. one offered by a webservice. In that case, an IQueryable result might not be an option at all. If you have such a hybrid data storage situation, you might want to avoid the IQueryable result type if this only works for the instances that are stored in a database, but not for instances retrieved from other storage. That is, if you find it problematic to expose a hybrid interface to your client(/service) layer (which I personally might).
Pascal Lindelauf
That's true, but because of the nature of web services, they usually call for a pattern other than repository, as they won't necessarily support the same kinds of queries, and chattier connections that return more data per request are more desirable. I usually use a DTO for web service calls, rather than risking a leaky abstraction.
JasonTrue