so it would have been impossible to switch out to another ORM (not
that we wanted to)).
That seems wrong. A major advantage of the repository pattern is that you hide the data access logic and that it is easily exchangeable.
So far it feels as though I put my business logic in my domain model
and via repositories I would work with the ORM (which ever I chose).
However, if I wanted to continue to use the MDA tool for the ORM part
of the application, the model created here would be very anemic (i.e
not contain any business logic). Similarly if I used Entity framework
(.net) or NHibernate for my ORM it too would be an anemic model.? I am
not sure where you would put the business logic if I just used
NHibernate.
An anemic domain model is considered a bad practice by many, for example by Martin Fowler. You should avoid such a design because such a model leads to procedural design techniques rather than a good object oriented design. You then have data classes and manager/processing classes which means you separated state and behaviour. But an object really should be "state and behaviour".
NHibernate does a great job at persistence ignorance. You can hide away the mapping details in XML or with FluentNHibernate and just write plain POCOs. It's very easy to create a rich domain model with NHibernate. I think you can do that with entity framework and the MDA tool, too. As long as this tool produces partial classes you can extend the generated code pretty easily without having to worry that a new generation might destroy your user-written code.
To cut this long story short. When you use NHibernate, nothing, I repeat nothing, stops you from embracing a rich domain model. I recommend using it with FluentNHibernate and mapping by hand. The mapping code takes only 5 to 10 minutes to write. I suppose that the very same is true for entity framework and that its tools at least create partial classes that are easily extensible.
Am I correct in thinking this way, in other words with DDD all the
business logic in the domain and just use the ORM for persistence via
repositories?
For the most part you are correct. You should have a rich domain model. Especially when things become more and more complex, it's easier to maintain and extend when you've designed it properly. But do keep in mind that DDD also knows (Domain Layer and Application Layer) Services to implement business logic and Factories to encapsulate creational logic.
I also tend to differentiate business logic into domain logic and actual application business logic. The domain logic is how the domain interacts and behaves while the application logic, which is a completely different layer, encapsulates how the domain is used for the specific use-case/application. Often times I have to update the domain model to support specific use cases and to make it more powerful.
I have an AR and I can't figure out the best way to create/edit some of the complex aggregates contained in it.
Caution: your spelling is off. AR don't contain aggregates, the naming is the other way around.
An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes. Each AGGREGATE has a root and a boundary.
Conceptually, the aggregate is a graph of (possibly complex) entities, with the aggregate root being one of those entities in the graph.
Also: value objects are usually immutable - you shouldn't have setters.
So when I go to add my CRUD methods to the Aggregate Root Load, I'm lost on how best to achieve this goal. I could add the following, but it doesn't seem like the DDD way to solve this problem because outside of the domain should not know what Run is right?
There are a couple possible answers to the riddle.
In this model, you seem to have a lot of properties that you need to reference to get anything done. So something like a http message that describes a change is going to have a complicated json document.
One way to turn that document into something that the model understands is to use a builder pattern. You give the application little mini factories to build up the data structures that it needs to talk to the model. That's a perfectly reasonable thing to do.
Another possible answer is to examine your model more carefully; domain models are primarily about change; they aren't glorified document stores. Information that the model doesn't need should be stored in a document somewhere else. For example, if a Run is a response to an "Order", then the Run might have a copy of the order number and a copy of the data that it actually needs to do its work, but not everything else.
(In the same vein: if you have a CustomerId in your value, you probably don't also need a Customer value. Use the id to look up the details you don't normally use.)
Unfortunately most of the Run information will be needed by the model.
If that's so, then it is, and you'll have to manage it. But push back on that assumption -- if you confuse the data you need to make a decision with the data you need to create a view, you are going to end up making more work for yourself.
Would the factories go in the domain layer?
It's a reasonable first guess - we usually start out with an assumption of one implicit collection of agnostic primitives (whatever language we happen to be coding in at the time). Evans coupled aggregates, repositories, and factories together in chapter 6 of the blue book, considering them all to be part of the domain layer.
I think it's a bit more correct to think of these factories as part of an adapter that allows the application to communicate with the model.
Best Answer
To be clear, I said "In F#, we tend not to use an object-relational mapper (ORM)" but not because of any validation issues, rather because a big ORM like Entity Framework is heavily object-oriented (surprise!) which doesn't always mesh well with a functional paradigm. Instead F#ers will either use type providers or a simpler library such as Dapper.
In the "Working with Relational Databases" chapter, I do say that you can treat the database in two different ways:
Which case applies depends on whether the database is shared with other applications, how it is designed, etc.
Update: I realize that the following sentence could be misinterpreted:
What I meant by that is that translating a domain model directly to a database via an ORM means that you lose a lot of the complexity of the domain types -- the "make illegal states unrepresentable" design approach that I dedicate a chapter to. This is because ORMs don't know how to handle single-case unions with constraints, complex choice types, etc.
Instead, I recommend that you translate your domain objects to a type specially designed for persistence (a "DTO") and then use that DTO for persistence, not the domain type. To store/load the DTO you can certainly use EF or NHibernate, but you're not getting much value from it when you use it that way, and so it's generally easier to use type providers or a lightweight mapper like Dapper.