Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple or Single Repositories with LINQ

I've been reading Chapter 11 (Testable Design Patterns) in the Professional ASP.NET MVC 1.0 book. In the examples in this chapter, data access is split into a number of repositories: IOrderRepository, IProductRepository, etc. That all makes sense: a single repository for a single class of data.

However, this breaks down somewhat for me when you consider the links between the tables: an Order contains a number of Products. When the Order class is created by LINQ-to-SQL, the order class will have a Products collection that enumerates all of the products related to that order. So by using this collection we're bypassing the ProductsRepository.

Therefore when mocking, I'm going to not only have to mock the OrderRepository and the ProductRepository, I'm also going to have to populate the Products collection in the returned Order objects. Which means that the mocked OrderRepository has to know about the mocked ProductsRepository and so on.

It seems a waste to ignore these collections that LINQ so kindly created for me, so my question is, in this case wouldn't a single repository make more sense?

like image 218
Grokys Avatar asked May 26 '09 11:05

Grokys


2 Answers

Your problem description is a typical textbook example of when too much blabla about 'this is good, that's bad' becomes the reason why a developer creates the software the way it's created instead of looking at the problem at hand and create software to fix that problem.

Case in point: your problem description isn't your problem to solve: you have an application to create for your client, that's the problem you should solve. If your choice of tools make your life hard, kick them out and use what works: if mocking doesn't work, why bother? Oh, because someone said your software will suck if you don't mock? Why?

You picked up some DDD things here and there, but you've missed some important parts: Product is an aggregate root. This means that you should obtain products from its own repository. Yes, that mitigates the navigation feature in the model, but that's DDD for you, IF you create the repositories strictly how the second part of Evans' book is dictating. But... should you?

If you can't answer why Product has its own repository, yet you can navigate to products from Order, you shouldn't create repositories for aggregate roots. WHY is that repository there? If it's there, shouldn't it be the ONLY point where Products are obtainable? (so also not through lazy loading!).

This indeed will create a lot of overhead and code you likely won't need (so ironically, YAGNI in full effect).

Ok, enough ranting. DDD is all about thinking. So the domain should drive the design, and by practicing that, you'll get a domain model which is representing reality. That's not to say you should implement a lot of code just because you read somewhere you should. Instead, if you have recognized the domain elements, the aggregate roots etc., you then have to place behavior for these types somewhere, e.g. inside the domain classes. You can place fetch logic in separate classes like order oriented fetch logic in an Order repository, but it won't be a repository in the strict sense (e.g. it doesn't have its own local cache etc. ). That's not that bad, it's all about what you should create for your client.

So, first: think, second: think, and third: think... again. What seems logical for you. Make a list of pros/cons of the options you have and choose the one which seems the most right for you. Document that choice and why you picked that one and not the alternatives. This gives way more value to maintainers than any other source: you document the alternatives and why you didn't pick them, you do research what will work for you, and you chose one.

Software engineering isn't hard, it's just that nowadays it seems fashion to simply do first and think later, without proper reasoning why one would do it that way and not the other way.

Good luck :)

like image 89
Frans Bouma Avatar answered Jan 06 '23 15:01

Frans Bouma


Other factors to consider include the likely lifespan of the product and the likelihood of having to change from LINQ-to-SQL to some other O/R mapper at any point in the lifetime. The smaller the project, the less critical the product, the less you need to worry about abstracting minutae to the nth degree.

like image 37
Jay Avatar answered Jan 06 '23 15:01

Jay