views:

147

answers:

3

When using Linq2Nibernate is better to make you Repository return a IQuerable?

My understanding is that if you use Linq to Nibernate the the query will not "fire" until you call .First() or Single() ect ect. So would it not be best to return IQuerable from all you Interfaces so you can build up\manipulate the expression tree before it fires?

My Repositories are called by a services and inherits from IServicie.

EDIT:

First I really appreciate all the answers. But I wan to add a little to the question. I am for this design. I don't fully understand the reservations around testing. As long as the process is tested at every point IE every filter point then I don't really see much of a difference.

addition:

Is there any point to Using Linq2Nibernate if your repository doesn't return IQuerrable?

+3  A: 

Personally, I think not. The problem with exposing composable queries from your repository is that you can no longer fully unit test them - their behaviour (and success) is now at the mercy of the caller. For example, they might do .Where(x=>SomeUnmappedMethod(x)) (with no translation). I added more on this here.

If you have fixed methods that return (for example) IList<T> or T[], then you can be sure that if it works in the unit test, it should work for real (barring any configuration errors). It also means that you can profile the DAL in isolation and have reasonable confidence what SQL (etc) is going to be executed. You can't profile/optimise a DAL that changes based on the caller.

(based on my LINQ-to-SQL usage; not LINQ-to-NHibernate specifically)

Marc Gravell
regarding isolation, wouldn't you still be exposed to the caller accessing relations you haven't loaded?
eglasius
I understand what your saying REALLY appreciate your input, but isn't that not really making full use of Linq2Nibernate? I can't really see any benefit in using it if you can't apply a "pipes and filter" type pattern PRE database fetch
Ted Smith
@Ted you use a specification pattern, which can work on a pretty similar way ... basically you pass those filters to the method (as opposed to applying them after calling the method)
eglasius
@Marc you might want to clarify those are integration tests, see chad's edit and my comment on it
eglasius
You can use the full LINQ stuff *inside* the repository... or use IQueryable - up to you...
Marc Gravell
@Freddy - I'd argue that checking the DAL can do its job is a unit test; I want to **avoid** the need to do an integration test between the consumer and the repository - and that is what is needed if you expose IQueryable
Marc Gravell
@Marc I understand what you mean and I do agree, calling tests that access external systems unit tests usually misguides people though :( - please check what I posted here: http://stackoverflow.com/questions/589603/how-can-i-improve-my-junit-tests/589620#589620
eglasius
+1  A: 

It depends on what's consuming your "Repository" (quotes because of ambiguity). I would say if something like your last layer (UI) is consuming your repository classes to NOT return an IQueryable. However if you have another layer between your UI layer and your Data Access layer I'd say yes, return IQueryable and have your middle layer handle the execution of the query.

EDIT

As for testing your Data Access Layer (DAL)/Repository I would say for the most part unless you have actual logic (if statements etc) there should be little to no testing. At that point you're testing the framework. My suggestion would to be put another layer between your accessing layer (UI) and the DAL like a BLL or something that handles the execution of the IQueryable queries. That way your repository can return queries and your BLL can handle executing them and maybe doing some logic which can then be tested.

Chad Moran
in this case it's not testing the framework, it's doing integration testing - ensuring it is working with the current version of the database i.e. someone didn't make a chance that broke it ... I was concerned with marc calling it "unit" testing, which is a wrong view for that
eglasius
A: 

I don't go with IQueryable, but I would explain why I do a bit differently:

  • Easier to mock the repository, to test the other code that uses it
  • Integration tests - most of the stuff that causes a query to be fired is in the repository, so I can do some really focused integration tests against it
  • Related to the first, easier to check the code is doing appropriate calls to the repository. This is because the calling code would pass the filters information to the repository method call, as opposed to applying them against the results.
eglasius