Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I've just had to switch out an ORM and it was a relatively daunting task, because the query logic was leaking everywhere. If i'd ever had to develop a new application, my personal preference would be to encapsulate all query logic (using an ORM) to futureproof it for change. Repository pattern is quite troublesome to code and maintain so i was wondering if there are any other patterns to solve the problem ?

I can foresee posts about not adding extra complexity before it's actually needed, being agile etc. but i'm only interested about the existing patterns solving a similar problem in a simpler way.

My first thought was to have a generic type repository, to which i add methods as needed to specific type repository classes via extension methods, but unit testing static methods is awfully painful. IE:

public static class PersonExtensions
{
    public static IEnumerable<Person> GetRetiredPeople(this IRepository<Person> personRep)
    {
        // logic
    }
}
share|improve this question
5  
What exactly is it about the Repository pattern that you find troublesome to code and maintain? –  Matthew Flynn Jan 1 '13 at 23:42
    
There are alternatives out there. One such is using Query Object pattern which although I haven't used seems like a good approach. Repository IMHO is a good pattern if used right but not the be all and end all –  dreza Jan 2 '13 at 6:14
add comment

4 Answers

up vote 7 down vote accepted

First of all: A generic repository should be considered to be a base class and not complete implementations. It should help you to get the common CRUD methods in place. But you still have to implement the query methods:

public class UserRepository : EntityFrameworkRepository<User>, IUserRepository
{
    public UserRepository(DbContext context){}

    public ICollection<Person> FindRetired()
    {
        return context.Persons.Where(p => p.Status == "Retired").ToList();
    }
}

Second:

Do not return IQueryable. It's a leaky abstraction. Try to implement that interface yourself or use it without knowledge about the underlying db provider. For instance, every db provider has it's own API for eagerly load entities. That's why it's a leaky abstraction.

Alternative

As an alternative you can use queries (for instance as defined by the Command/Query separation pattern). CQS is described in wikipedia.

You basically create query classes which you invoke:

public class GetMyMessages
{
    public GetMyMessages(IDbConnection connection)
    {
    }


    public Message[] Execute(DateTime minDate)
    {
        //query
    }
}

the great thing with queries is that you can use different data access methods for different queries without cluttering the code. you can for instance use a web service in one, nhibernate in another and ADO.NET in a third.

If you are interested in a .NET implementation read my article: http://blog.gauffin.org/2012/10/griffin-decoupled-the-queries/

share|improve this answer
    
Wouldn't the alternative pattern You suggested create even more clutter on larger projects seeing as what would be a method in the Repository Pattern is now a whole class ? –  Dante Jan 2 '13 at 15:19
1  
If your definition of having small classes is cluttering, well yes. In that case you should not try to follow the SOLID principles either as applying them will always produce more (smaller) classes. –  jgauffin Jan 2 '13 at 15:23
1  
Smaller classes are better, but wouldn't the navigation of existing query classes be more troublesome, than to say, browsing the intellisense of a (domain) repository to see, if the neccessary functionality lies in there and if not, implement it. –  Dante Jan 2 '13 at 15:32
1  
The project structure becomes more important. If you put all queries in a namespace like YourProject.YourDomainModelName.Queries it will be easy to navigate. –  jgauffin Jan 2 '13 at 16:11
add comment

First think I say is that ORM is already big enough abstraction over your database. Some ORMs provide binding to all common relational databases (NHibernate has bindings to MSSQL, Oracle, MySQL, Postgress, etc..) So building new abstraction on top of it doesn't seem profitable to me. Also, argummenting, that you need to "abstract away" this ORM is meaningless.

If you still want to build this abstraction, I would go against Repository pattern. It was great in age of pure SQL, but it is quite troublesome in face of modern ORM. Mainly because you end up re-implementing most of the ORM features, like CRUD operations and querying.

If I was to build such abstractions, I would use these rules/patterns

  • CQRS
  • Use as much as possible of existing ORM features
  • Encapsulate only complex logic and queries
  • Try to have "plumbing" of the ORM hidden inside an architecture

In concrete implementation, I would use CRUD operations of ORM directly, without any wrapping. I would also do simple queries directly in code. But complex queries would be encapsulated in their own objects. To "hide" the ORM, I would try to inject the data context transparently into an service/UI objects and have same done to query objects.

Last thing I would like to say, is that many people use ORM without knowing how to use it and how to make best "profit" out of it. People recommending repositories are usually of this kind.

As a recommended reading, I would say Ayende's blog, especially this article.

share|improve this answer
add comment

The problem with the leaky implementation is that you need many different filter conditions.

You can narrow this api if you implement a repository method FindByExample and use it like this

// find all retired persons
Person filter = new Person {Status=PersonStatus.Retired};
IEnumerable<Person> found = personRepository.FindByExample(filter);


// find all persons who have a dog named "sam"
Person filter = new Person();
filter.AddPet(new Dog{Name="sam"});
IEnumerable<Person> found = personRepository.FindByExample(filter);
share|improve this answer
add comment

Consider making your extensions operate on IQueryable instead of IRepository.

public static class PersonExtensions
{
    public static IQueryable<Person> AreRetired(this IQueryable<Person> people)
    {
        return people.Where(p => p.Status == "Retired");
    }
}

To unit test:

List<Person> people = new List<Person>();
people.Add(new Person() { Name = "Bob", Status = "Retired" });
people.Add(new Person() { Name = "Sam", Status = "Working" });

var retiredPeople = people.AsQueryable().AreRetired();
// assert that Bob is in the list
// assert that Sam is not in the list

No fancing mocking required for testing. You can also combine these extension methods to create more complex queries as needed.

share|improve this answer
1  
-1 a) IQueryable is a bad mother, or rather a GOD interface. Implementing it is very had and there are very few (if any) complete LINQ to Sql providers. b) Extension methods make extension (one of the fundemental OOP principles) impossible. –  jgauffin Jan 2 '13 at 8:33
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.