Basic ddd question on dealing with data in domain objects?

1,561 views
Skip to first unread message

Ncage

unread,
Jun 23, 2013, 7:56:19 PM6/23/13
to ddd...@googlegroups.com
This is a 101 type of question on DDD. 

My question has to deal with loading ddd objects and loading those objects with data. In general do most people pass maybe an IRepository into the domain objects so the domain so the domain object can interact with the database directly  or does the data get passed in through the constructor and all selecting/updating/inserting/deleting of data happen outside the domain object?

Secondly i'm grappling with just using the repository pattern or using an ORM directly. Of course if you use the ORM directly then you are tying your code to the ORM (in my case since i use .Net either NHibernate or Entity Framework) but if you don't use an ORM and you have either complex queries with many different types of criteria you would either have to deal with the complexities of a query object or have many methods off of your repository that would represent all the combinations. In one of Ayende's famous posts (http://ayende.com/blog/3955/repository-is-the-new-singleton) he recommends just ditching the repository and using the ORM directly but something about typing my code to an ORM bothers me for some reason. Worse if your domain objects are dealing with data directly (1st question above) then your tying your Domain Objects to the ORM.

Any help would be appreciated....

Michael Brown

unread,
Jun 24, 2013, 12:59:20 AM6/24/13
to ddd...@googlegroups.com

There are a number of implementations of the Repository pattern over EF and NHibernate. I’ve done a post which I have to import into my new blog that shows how easy it is when using the Repo/UnitOfWork patterns together to switch between InMemory (for unit testing), EF, and NHibernate as your store. The upside is that you don’t have to build your own query object, .NET has one built in via LINQ (which both NHibernate and Entity Framework support).

 

As for loading your Domain Objects, the repository is responsible for doing that. And using NH or EF as your backing store, you get change tracking, lazy loading, and a lot of other benefits out of the box.

 

At this point, I’d actually recommend EF over NH. The migrations and other features that have come with the recent releases places it ahead.

 

Hope this helps,

--Mike

 

Wim van Gool

unread,
Jun 24, 2013, 3:08:31 AM6/24/13
to ddd...@googlegroups.com
My advise is also to use the repository-pattern. One of the great benefits is that it's meant to hide the infrastructural details concerning loading and saving your aggregates, so those concerns don't end up in your domain. Then only put your repository-interfaces in your domain model, and put your repository-implementations in another assembly. This works well if you are applying the onion-architecture/port-and-adapters, which I recommend highly for DDD-projects. This setup also enables you to easily test your domain behavior (stubbing your repositories where necessary).

You can then choose to implement your repositories using an ORM such as NHibernate or EF, but before you do, you should ask yourself if you even need one. That is, if you split your writes from your reeds (CQRS) and choose not to use a relational schema behind your write model, you can downright avoid the ORM-requirement at all, which makes life easier in some areas but a bit harder in others. If you decide you can't avoid/want to use a relational schema, then choose the ORM you are most comfortable with. EF has got great versioning-tools in it's latest releases, but it's a lot less 'persistant ignorant' than NHibernate (it demands properties to map and has very limited mapping capabilities for non-primitive types, which can be a pain in the ### if you want a clean model).


--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Stijn Volders

unread,
Jun 24, 2013, 5:50:48 AM6/24/13
to ddd...@googlegroups.com
The Repository pattern and complex queries are often a burden. 

I try to use dedicated services to do complex queries & don't implement this in my repository. What data storage you're using behind this service and how you access is up to you and that's the kind of freedom I like.




2013/6/24 Wim van Gool <vang...@gmail.com>

Jörgen Andersson

unread,
Jun 24, 2013, 10:52:32 AM6/24/13
to ddd...@googlegroups.com

Hi,

To me an important aspect is to keep technical concerns, such as DB-integration, out of the domain model. It is a way to control complexity. Therefor I do not see tying the domain objects to an ORM being an alternative. In this post I write a bit about the style I've been using: http://se-thinking.blogspot.se/2012/09/ddd-on-top-of-services-ddd-inside.html

Jörgen

--

Ncage

unread,
Jun 24, 2013, 11:35:59 AM6/24/13
to ddd...@googlegroups.com
Thanks Mike. I would be very interested to read your blog post once its published. Do you think you will have it published anytime soon? What its the url for your blog? I thought if you used EF/NHibernate behind a repository then you would loose LINQ but i guess i was wrong :). I'll be interested to read about your solution. Where is the url for your blog?

Ncage

unread,
Jun 24, 2013, 11:36:57 AM6/24/13
to ddd...@googlegroups.com
SQL Server. 

João Bragança

unread,
Jun 24, 2013, 11:43:19 AM6/24/13
to ddd...@googlegroups.com
What is your use case for retrieving an aggregate by anything other than its id? I can understand that sometimes this is the case, e.g. loading an account by its account number rather than a surrogate id. But you don't need LINQ for that..


--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Ncage

unread,
Jun 24, 2013, 11:46:04 AM6/24/13
to ddd...@googlegroups.com
Plan to definitely learn CQRS in the future but taking baby steps. I know some of the concepts but, as of yet, don't have a clear picture. For example how to do CQRS for a system where we run some very massively data intensive processes (payroll systems) that write out more than 300,000 records each times it runs. I'm sure when i start researching CQRS i will have many questions though :)

Kijana Woodard

unread,
Jun 24, 2013, 11:56:57 AM6/24/13
to ddd...@googlegroups.com
You are right to keep persistence out of your domain model. IRepository is persistence. Keep it out of your domain model too.

The generic repository over an ORM fails because either you give up all of the features the ORM has to optimize scenarios or you leak through implementation details and your repository is no longer generic/swappable.

If all you want to do is kv Save/Get by id, find/replace will work just fine when you want to do switch from ef to llblgen or whatever.

If you are doing things that are more complex, the generic repository will fight you all the way. It will be much harder for team members to contribute and you'll end up with one person as a bottleneck doing all the "important" repository changes.

Use DDD. Model classes that know how to fulfill scenarios within a given context. What's more, there's nothing that says that two BCs _must_ share the same persistence. Why can't one be SQL Server and another use MongoDB? 

Speaking of that, no generic repository is going to allow you to casually cross the conceptual divide between something like MySql to Redis to MongoDB. You will probably need to rethink large portions of your implementation to match the demands and benefits of different persistence technologies.

Once you start breaking your app down by BC and realizing they don't need to be connected in a monolithic db, other possibilities start to flow. Events, eventual consistency, etc. Suddenly you are doing CQRS and you didn't realize it. :-)

Use your command handlers or some persistence specific object that is injected into the command handlers to talk as directly to your persistence as possible. This will make it easy to maintain, easy to modify, easy to optimize, and easy to replace. 

Who knows, you might start using Dapper. 

Ncage

unread,
Jun 24, 2013, 12:18:40 PM6/24/13
to ddd...@googlegroups.com, joao...@braganca.name
Oh my too many to list:

By Date Range on different dates (status dates, updated dates, fiiscal years)
By Status of different records
By flags on different records.
By priority
By Type.
By owner of records
By amounts of different records

I mean the list goes on and on and on. We have over 300 tables and are VERY query heavy. Its not unheard of to have over 20 joins (which several nested queralated subqueries

Kijana Woodard

unread,
Jun 24, 2013, 12:37:06 PM6/24/13
to ddd...@googlegroups.com
"Its not unheard of to have over 20 joins (which several nested queralated subqueries"

Being able to optimize will be important. The generic repository will inhibit optimization. Frankly, sticking only to ORMs will inhibit optimization. I'd seriously consider a judicious sprinkling of stored procs and dapper in addition to the boring queries that can easily run through an ORM. Set things up so you can make this decision independently for each scenario without risking changing behavior across the app.

Stijn Volders

unread,
Jun 24, 2013, 1:02:06 PM6/24/13
to ddd...@googlegroups.com, ddd...@googlegroups.com
+1. Don't use an ORM for that. 

Ncage

unread,
Jun 24, 2013, 2:58:05 PM6/24/13
to ddd...@googlegroups.com
Thanks Kijana thats exactly what i was thinking but without seeing some actual code its really hard to visualize how things are working. Conceptually it makes a lot of sense but without seeing any code it still seems kind of theoretical to me at this point (Model Classes that know how to fullfill scenarios in a given context?) . If you don't have the repository in the domain then how are you loading up the objects with data? When you have to persist your changes in your domain objects to storage  would you have a bunch of getters on the domain objects that you read from? Do you have a constructor on your aggregate root that has parameters the load up the object? If we could lets try to leave CQRS out of it. Just more new concepts i have to try to grapple with and is more likely to confuse me :). So say in the traditional N-Tier approach:

In your service/application layer would you feed data from your repository into your Aggregate root?

So to make thing simple say you have a customer sales bounded context that just has orders and order details

Public Int GetSalesByCustomerId(int customerId)
{
  
      var orderRepo = New OrderRepo(conString);
      
     // DTO/POCO Type objects returned from the repository
     var orders = orderRepo.GetAllOrdersByCustomerId(customerId);

    List<OrderDomain> domainOrders;

    orders.ToList().ForEach( o => {
                                                   //somehow pass all the data from o into the order domain below
                                                   var domainOrder = new OrderDomain(....data loading parameters);

                                             }
                                      )
   

   return domainOrders.Sum(o => o.CalcOrderTotal());  

}

Maybe if a seen a little code snippet where the domain is actually getting loaded with data it would make much more sense. Do you have a link?

Kijana Woodard

unread,
Jun 24, 2013, 4:25:26 PM6/24/13
to ddd...@googlegroups.com
The code there looks like select n+1 problems in the making. I'd try to get all that data aggregated on the server and make one remote call to the db. If using a document database like raven or mongo, the order total would be part of the document and then I'd either use m/r or some persistence feature like raven's AggregateOn to do the sum.

It sounds like you're heavily invested in rdbms so, I'm thinking of something like (dapper-ish code):

Public int GetSalesByCustomerId(int customerId)
{
     return cnn.Query<int>("spGetSalesByCustomerId", new {Id = customerId}, 
        commandType: CommandType.StoredProcedure).First();
}

Jef Claes

unread,
Jun 25, 2013, 8:22:56 AM6/25/13
to ddd...@googlegroups.com
I believe there can be value in most of these flavors. 

A repository often is a part of the language; "I get the order by customer number, and mark it as processed." In this regard I believe an ORM without the repository abstraction can be just as efficient; Session.Query<Order>().Where(x => x.CustomerNumber == customerNumber). The hairiest queries can be encapsulated into a query object; new GetCustomer(customerNumber).Execute().

Another popular reason to use the repository pattern, is to make the ORM purely an infrastructural concern and implementation detail. I don't think there's anything wrong with that sentiment per se, but it often ends up being a rather leaky abstraction, often rendering it impossible to just switch ORM's without having a noticeable impact - think lazy loading, IQueryable implementations etc... That is, if you really trust the ORM to do the relational mapping, instead of using it as a tool to hydrate your real aggregates. 

People also like fast tests, and that's why they like using a persistence pattern that allows to switch out real implementations with in-memory ones. If you use a repository you have full control over this. But there are techniques that allow you to do that for NHibernate's session and EF's DbContext. I'm using RavenDB right now, and there it comes out the box; using an in-memory database running for my tests is trivial. Also take into consideration, that switching out your repository, forces you to write two sets of tests; unit tests, plus integration tests for your repository. The value gained is often marginal separating them, and just a single integration test gives you more bang for the buck.

These are the trade-offs that I consider when I'm picking the right strategy. At the moment, I'm using RavenDB _without_ abstractions, and it has been working just fine. You can still introduce abstractions later on too..

Regards
@jefclaes

Wim van Gool

unread,
Jun 25, 2013, 8:52:40 AM6/25/13
to ddd...@googlegroups.com
People also like fast tests, and that's why they like using a persistence pattern that allows to switch out real implementations with in-memory ones. If you use a repository you have full control over this. But there are techniques that allow you to do that for NHibernate's session and EF's DbContext. I'm using RavenDB right now, and there it comes out the box; using an in-memory database running for my tests is trivial. Also take into consideration, that switching out your repository, forces you to write two sets of tests; unit tests, plus integration tests for your repository. The value gained is often marginal separating them, and just a single integration test gives you more bang for the buck.

Although I'm sure the ORM- and other frameworks related to persistance provide more and more features to support fast tests, I still think it's a lot easier to hide the frameworks behind repository-interfaces when testing system behavior. You are right that, in the end, you also want to test the mapping code with some integration tests, but for this, I don't really need 'an extra set of tests' - that is, tests that are inherently different than my other tests. I auto-test my infrastructure by running all my happy flow tests again, but now by swapping in my   real repository-implementations. This way, I get 95% of my testcode of the integration tests for free. :-)


--

Kijana Woodard

unread,
Jun 25, 2013, 9:12:38 AM6/25/13
to ddd...@googlegroups.com

I've found the easiest to be an in memory db for tests. Still not perfect, but better in terms of modeling real scenarios without having to try and mimic the persistence behavior through mocks/fakes. If the repository is chunky (give me this view model) as opposed to generic (Get<T>), mocking the repo will work fine. I just don't like classes with a single method call that get used in one place in an app just 'for testing'. Anemic.

Wim van Gool

unread,
Jun 25, 2013, 9:26:00 AM6/25/13
to ddd...@googlegroups.com
I agree, I never Mock repositories. I just swap them with InMemory-implementations when I'm testing domain model behavior.

Greg Young

unread,
Jun 25, 2013, 12:15:48 PM6/25/13
to ddd...@googlegroups.com
If you are using bunches of lazy loading you likely have bigger problems. Why do you need lazy loading if you have reasonably modeled aggregates?
--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 


--
Le doute n'est pas une condition agréable, mais la certitude est absurde.

Kijana Woodard

unread,
Jun 26, 2013, 11:41:24 PM6/26/13
to ddd...@googlegroups.com
Ncage said 
"Hmm maybe i made my example a little to simplistic. I tried to make it simple rather than delving into a complex object hierarchy. Here your just calling a stored procedure to do the sum. So pretend there was complicated logic you had to do on each order detail and you had to do that logic in the order detail class and not on the database (of course business logic shouldn't be in the database) when you were calculating the sum. Say the aggregate root is order. "

I would try to avoid complicated logic while building a screen. In fact, I'd want to keep my "domain objects" out of it. If I was using a document database, I'd calculate the order total during write in the order document. Then I'd probably use m/r or a feature of the persistence engine (e.g. AggregateOn for Raven) to get the total order value for a customer. Given an rdbms without "read models", I'd probably sproc there to limit the number of remote calls with 1 being preferable.

But really, I'd be drilling into what the intent is for the screen. The implementation can change depending on whether we're trying to build a list of  "high value customers" vs "customers who meet criteria for a marketing campaign" vs "crm". DDD / user stories.

Once you start thinking of screens as report, things start to open up. I have my "domain objects" for writes and I can read in a variety of ways depending on the scenario at hand. The fact that the data for the read is the same data for the write is entirely coincidental. And suddenly, you've started toward "cqrs".

Bennie Kloosteman

unread,
Jun 27, 2013, 12:20:49 AM6/27/13
to ddd...@googlegroups.com
Kijana wrote "

Being able to optimize will be important. The generic repository will inhibit optimization. Frankly, sticking only to ORMs will inhibit optimization. I'd seriously consider a judicious sprinkling of stored procs and dapper in addition to the boring queries that can easily run through an ORM. Set things up so you can make this decision independently for each scenario without risking changing behavior across the app."


Not necessarily i have had huge issues with deployment of large amounts of stored procs in multi team scenarios ..and unless you have a dedicated DBA team that works on optomizing and securing them i dont think they are worth it  ( RAD Reports excepted) .. 

With ORM i find using Select * and caching whole tables/ sets ( or frquently used subsets)  and then using code to filter / search on them can get superior optomization results and better code reuse /maintability. Especially if you are dealing with eventual consistancy.

I always wonder that most DBs easily fit in server memory so why do we even use ORMs , SQL etc .. once you throw out ACID /transactions it seems the benefit is more about backup /restore  and organizational lines , but with event sourcing you  need these less and can reload he read DB from replays as a "restore".  I note the LMAX guys used a plain old file for  event sourcing storage for each day ..  And i have had some success with simple client apps just loading and saving and loading an object model to an XML file ( with backup)  , lot easier than managing a DB on clients . 

Kijana Woodard

unread,
Jun 27, 2013, 12:41:29 AM6/27/13
to ddd...@googlegroups.com

Personally, I reserve stored procedures for edge cases. Also, I prefer smaller, decoupled databases by BC rather than a single monolithic db. But, since the OP mentioned 300 tables and complex read scenarios, I figure one has to make do with that.

I'd hope that a web server doesn't have enough memory to hold a 300 table db, but I take your point. Most solutions are over engineered. By breaking systems down into smaller apps, it becomes easier to see how simple solutions can be effective.

Reply all
Reply to author
Forward
0 new messages