views:

87

answers:

4

I'd like to expose a Repository as an 'IQueryable' type.

The repository uses Linq to NHibernate to communicate with the database.

Can anyone point me at an example implementation?

For example, what would the corresponding 'GetEnumerator()' implementation on my repository look like?

Edit:

Would something like this be appropriate?

public class MyTypeRepository : IEnumerable<MyType>
{        
    IEnumerator<MyType> IEnumerable<MyType>.GetEnumerator()
    {
        return Session.Linq<MyType>().GetEnumerator();
    }


    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable<MyType>)this).GetEnumerator();
    }

}
+1  A: 

Just return session.Linq<T>()

Thomas Levesque
If you do this make sure you're careful with where the Queryable gets passed around to so you don't accidentally create full table scans.
Chris Marisic
+2  A: 

I think a Repository can give you 1 or more IQueryables/IEnumerables, but not : a Repository is an IQueryable.

It could look like:

 public interface IPersonRepository
 {
    IEnumerable<Person> GetAllPersons();
    void AddPerson(Person person);

    // more...
 }

You could return IQeryable<Person> from GetAllPerson() but that may not be an improvement. IEnumerable is simpler, less coupling.

Henk Holterman
A: 

This is a bad design.

An IQueryable is a question (lookup "query" in a dictionary). It's how you ask for data. It's what you should be giving to the Repository.

A Repository should be returning answers -- the data itself.

If the Repository is returning a IQueryable, you've pretty much negated the need for the Repository.

James Curran
I don't agree with this assessment. If your repository exposes IQueryable objects, you can tell it how to query in an abstract way. That's how Linq to SQL works and I build repositories on top of that all the time.
BC
@BN: Your timeline is confused. If your Repos returns an IQueryable, how can you use that to tell the Repos anything? You've gotten your object from the Repository. You are done with it. Perhaps you meant this as a conversation: You get an IQ (from somewhere, maybe the Repos), you modify it, you give it back to the Repos, you get data. This cooresponds more to my version than yours.
James Curran
-1 An IQueryable object is something [that can be queried](http://en.wiktionary.org/wiki/queryable). It's not a query itself. By calling LINQ methods on the IQueryable, you're building an [Expression](http://msdn.microsoft.com/en-us/library/system.linq.expressions.expression.aspx) object. This Expression represents the query.
Niels van der Rest
@Niels: Your dealing too much with implementation details here, and anyway, again we go back to the timeline. A query (in whatever form) goes TO the Repository and data come OUT. That's the important issue here.
James Curran
@James: The data is *exposed* as an IQueryable, e.g. Entity Framework exposes database tables as IQueryables. Look at the statement `customers.Where(c => c.City == "London").Take(10).Average(c => c.Age)`. The `customers` variable is the full dataset. The `Where` statement filters the original data and results in a **new dataset**. This dataset is narrowed down further by the `Take` and `Average` statements. The fact that the entire statement *may be* converted to a single optimized SQL query, *that's* an implementation detail. But if you don't agree, we'll have to disagree.
Niels van der Rest
A: 

Lots of opinions of this one, but Ayende (Oren Eini) seems to think IQueryable is ok to return and articulates his point rather well.

Josh
And he doesn't have a Repository in that example. He has essencally eliminated his DAL. Which is fine, just don't call the vacuum left a DAL.
James Curran