views:

431

answers:

4

Using Linq to SQL, and a DDD style Domain Layer with de-coupled repositories, does anyone have any good ideas on how to implement a specification pattern without bleeding L2S concerns up into the domain layer, that is still understandable? :)

We have complex business logic surrounding the selection of a set of transaction data, and would like those rules/specifications to be owned by the Domain. We've also done a good job of keeping our domain persistence ignorant.

This presents a problem, because in order to implement a Specification, the domain (as far as I can tell) needs to see the types being queried (L2S types).

Any ideas?

Also, nHibernate is out of the question for reasons I don't want to explain.. :)

A: 

Linq-To-Sql classes can be partial. This means that you can extend them by implementing a partial that implements a common interface. That Interface can be shared between layers without the "bleeding" problem you are describing. The rest is just the details of your "IsStatisfiedBy" which should be easy to encapsulate.

slf
how about "leaking"? :)
jlembke
A: 

I recently had the same issue. Different pattern, but still LINQ to SQL (L2S). I tried two different ways to avoid the leakage.

First we tried using DTOs and a mapping layer. So we wrote super simple objects that had a one to one mapping to the tables. They were all decorated with L2S attributes. We then wrote a mapping layer to map the DTOs to our business objects. All of this was hidden via the Repository pattern from Doman Driven Design. So consumers of the business objects had no idea the L2S was under the hood.

Next, mostly for variety. We tried using the XML mapping features of L2S so the objects themselves needed no attributes. For collections we exposed IEnumerable instead of any of L2S collections. If you looked at the internals of the business classes you could still detect some usage of L2S (EntitySet or Ref). But consumers of the class had no idea. So some bits of leakage but nothing drastic.

In the end we stuck with the first pattern. The second worked and we could have replaced L2S without changing the interface of the business layer, but I was never happy with XML mapping. The first pattern had a much cleaner separation between the database and the business objects. It took more code. The first one also worked better for us because it allowed us to evolve the business objects differently than the tables. In the early days of the project the xml mapping worked because our objects were pretty much one to one with the tables.

So in the end we put a layer between L2S and the domain. It worked. It took more code, but it was really simple stuff. And it was all very testable.

Mike Two
I solved the problem of L2S leakage, but the issue now is how to have my domain objects own specifications (as in the Specification Pattern) without having to reference L2S from my domain layer.
jlembke
I guess I'm not seeing exactly where you're stuck. We use the first technique I mentioned to keep our domain and L2S far apart, and we are using the Specification Pattern. Our specifications act on the domain objects and we have DDD style services to get the specifications. Thanks to the mapping layer if those specifications need parameters from the database it is all hidden behind the mapping layer.
Mike Two
A: 

If you want to avoid referencing Linq2Sql from your domain layer, you must work against interfaces that represent your entities instead of working with the actual entities themselves. You then need a mapping layer between your interfaces and your entities.

I've worked this way and found it to be a severe hindrance. I switched to NHibernate for new projects and for the older projects I simply stopped worrying about the domain referencing Linq2Sql entities directly. Overcoming that restriction is simply too much of a time-cost in my opinion.

Nathan
nHibernate is probably the real answer. thanks Nathan..
jlembke
We currently have our domain in a separate assembly, and the L2S is hidden behind a repository implementation. The domain assembly has no references to the datacontext or anything L2S at all. So we are successful there.I may be thinking wrongly about the Specification Pattern, but I was trying to pass in specifications to the Repository, yet have the Domain Layer own those specifications.L2S creates it's own types, so in order to write a specification, I'd have to reference those types, and that would leak those concerns into my domain.Sounds like nHibernate would get around that.
jlembke
+1  A: 

Have you considered mapping your generic Specifications into an Expression tree that would translate into proper L2S syntax? It seems that is the main problem you are hitting here. The Specification pattern isn't the problem, but the mapping to L2S is.

Brett Veenstra
good thought. I'll look into that.
jlembke