20

I have read recently that it is not good practice to use the repository pattern in conjunction with an ORM. From my understanding this is because the abstraction they provide over the SQL database is too leaky to be contained by the pattern.

I have a couple of questions about this:

  1. What do you do if you want to switch out ORMs? You would have ORM specific code in your application if you do not contain it in a repository.

  2. Is the repository pattern still valid when not using an ORM and you are using ADO.NET for data access and populating object data yourself?

  3. If you use an ORM but not the repository pattern where do you keep commonly used queries? Would it be wise to represent each query as a class and have some sort of query factory to create instances?

  • 1
    1) you will never ever be able to swap out an ORM due to their different behaviors, even if both support linq, they will behave different enough for your application to break. e.g. lazy loading behavior, dirty tracking, ghost proxies etc.. It is however nice to be able to swap out the ORM for an in-mem implementation for testing.. – Roger Johansson Dec 30 '13 at 12:16
  • For what it's worth, my take on the Repository/ORM discussion is here: stackoverflow.com/questions/13180501/… – Eric King Dec 30 '13 at 15:05
  • Where did you read that it is a bad practice? – Dave Hillier Dec 30 '13 at 16:24
3

1)True, but how frequently do you switch out an ORM?
2)I would say so, because an ORM context is sort of a repository and hides a lot of work involving creating queries, retrieving data, mapping, etc. If you don't use an ORM, that logic still has to reside somewhere. I don't know if that would qualify as the repository pattern in the strictest sense of the word though...
3)Encapsulating queries is something I see frequently, but that's usually more for testing/stubbing purposes. Other than that, I would be careful when reusing a query across different parts of an application, because then you risk creating a dependency on something which could change n-times (n being the number of places where you use the query).

  • 1
    1) You're asking the wrong question. It doesn't matter how often, it just has to be once. Given the number of ORM options available, there might be one that is better than what you're already using. The question now becomes: what happens when you do? Repository gives you a nice abstraction. I've been there and I wish I made such an abstraction in the first place. – devnull Oct 10 '13 at 13:29
  • 3
    @devnull I disagree. If it would happen at most once, I would consider it to be an acceptable risk. If you fear making the wrong choice: experiment more before committing to one. In theory, such an abstraction sounds nice, but in practice you wind up recreating a fairly large part of the api of your ORM, all because you may wind up choosing another one someday, somewhere. To me, that's wasted effort, redundant code and more code you yourself have to maintain and guarantee. Besides, switching an ORM shouldn't affect an entire application; learn to place domain boundaries. – Stefan Billiet Oct 10 '13 at 13:37
  • ORM change is not the only reason for repository. If you need to introduce [distributed] cache in your application - all changes will be done in repository and your BL will not change due to changes of data access layer. – Valery Oct 10 '13 at 14:33
  • wouldn't the distributed cache be built into the ORM in most cases ? – user1450877 Oct 10 '13 at 14:43
  • I think it depends on the ORM. You can decide to go with lighter ORM than NHibernate or EF. – Valery Oct 10 '13 at 14:55
2

1) What do you do if you want to switch out ORMs, you would have specific ORM code in your application if you do not contain it in a repository.

I haven't yet been in a position where company all of a sudden decided to switch data access technology. If this does happen, some work will be required. I tend to abstract data access operations through interfaces. Repository is one way to solve this.

I would then have a different assembly for concrete implementation of my data access layer. For example, I might have:

Company.Product.Data and Company.Product.Data.EntityFramework assemblies. First assembly would be used purely for interfaces, when another would be a concrete implementation of Entity Framework's data access logic.

2) Is the repository pattern still valid when not using an ORM and you are using ADO.net for data access and populating object data yourself ?

I think that it's up to you to decide which pattern is valid or not. I've used a repository pattern in the presentation layer. One thing to keep in mind is that people like to throw responsibilities into repositories. Before you know it, your repository class will be dancing, singing and doing all sort of things. You want to avoid this.

I've seen a repository class that started off by having GetAll, GetById, Update and Delete responsibilities, which is fine. By the time the project was complete, that same class had dozens of methods (responsibilities) which should have never been there. For example GetByForename, GetBySurname, UpdateWithExclusions and all kinds of crazy stuff.

This is where queries and commands come into play.

3) If you use an ORM but not the repository pattern where do you keep commonly used queries. Would it be wise to represent each query as a class and have some sort of query factory to create instances ?

I think it's a very good idea to have use queries and commands instead of repositories. I do the following:

  • Define interface for a query. This will help you unit test. E.g. public interface IGetProductsByCategoryQuery { ... }

  • Define concrete implementation for a query. You will be able to inject these through IoC framework of your choice. E.g. public class GetProductsByCategoryQuery : IGetProductsByCategoryQuery

Now instead of polluting repository with dozens of responsibilities, I simply group my queries into namespaces. For example, an interface for the above query may live in: Company.SolutionName.Products.Queries and the implementation may live in Company.SolutionName.Products.Queries.Implementation

When it comes to updating or removing data, I use command pattern in the same manner.

Some might disagree and say that before the project is complete you will have dozens of classes and namespaces. Yes you will. In my mind it's a good thing as you can browse through the solution in IDE of your choice and instantly see what kind of responsibilities certain component has. If you have decided to use a repository pattern instead, you will have to look inside each repository class trying to work out its responsibilities.

  • I like the idea of having commands instead of generic functions. Where can I read more about how to implement them in the context of data access? – dotslash Dec 31 '17 at 15:42
1

DISCLAIMER: What follows is based on my understanding and brief experience of said pattern (Repository that is). I might be doing it wrong...in fact, I'm pretty positive that I'm doing it wrong :). So, while this is an attempt for an answer, it is also a question in disguise.

I'm using the Repository pattern to abstract away the data access layer, which is in most cases an ORM. It is a generic interface, with methods for Create, Read, Update, Delete and implementation classes for LINQ to SQL and EF so far. I could make an implementation that writes to XML files on disk (just a wild example of what I could do with it). I'm not implementing Unit of Work since it's supported by the ORM's. If need be, I could probably implement it. I like it this way because, so far, it has given me a nice separation. I'm not saying that there aren't better alternatives.

To answer your questions:

  1. Whether you like it or not, change will occur. And if you've written a bunch of applications and time has come to maintain them, but feel that is a pain to work with the current ORM and want to change it, you'll praise yourself for making such an abstraction. Just use anything that you feel comfortable with, be it Repository or other pattern/concept.
  2. Yes it is, as long as you use it to separate data access. Like I mentioned earlier, you can make an implementation that writes data in flat files.
  3. I use the Repository to keep my commonly used queries and Query Objects for when I have queries that I want to tweak (which aren't that many).

To give you another example, the guys at Umbraco have abstracted away the DI container, just in case they might want to be switching over to something else.

0

If the ORM offers flexibility of LINQ, eager loading etc. I wouldn't hide it behind any extra layer.
If it involves raw sql (micro ORM) then "method per query" should be used anyway to achieve reusability, thus making repository pattern a good fit.

What do you do if you want to switch out ORMs? 
You would have ORM specific code in your application if you do not contain it in a repository.

Why would you need to switch?
The one that has most of the features you need should be used. It's possible that a new release of ormX brings new features and turns out to be better than the current one, but...
If you choose to hide the orm, you can only use the features all the candidates have in common.
E.g. you can't use Dictionary<string, Entity> properties in your entities because ormY can't handle those.

Assuming LINQ is used, majority of orm switch is just switching library references and replacing session.Query<Foo>() with context.Foos or similar until it compiles. Boring task, but takes less time than coding the abstraction layer.

Is the repository pattern still valid when not using an ORM and you are using ADO.NET for data access and populating object data yourself?

Yes. Code should be reusable and that means putting sql building, object materialization etc. in one place (separate class). You may as well call the class "XRepository" and extract an interface from it.

If you use an ORM but not the repository pattern where do you keep commonly used queries? 
Would it be wise to represent each query as a class and have some sort of query factory to create instances?

Assuming LINQ is used a class wrapper would be overkill IMHO. A nicer way would be extension methods

public static IQueryable<T> Published<T>(this IQueryable<T> source) where T : Page
{
    // at some point someone is going to forget to check that status
    // so it makes sense to extract this thing
    return source.Where(x => x.Status == Status.Published && x.PublishTime <= DateTime.UtcNow);
}

Any code that is used in multiple places (or has the potential) and is complicated enough (error prone), should be extracted to a centralized place.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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