I'm trying to setup my domain models around the DDD principles. Right now I have the following class:
class Customer : AggregateRoot
{
public string CustomerReference {get;set;}
public string CustomerName {get;set;}
public string List<Adult> Adults {get;set;}
public string List<Child> Children {get;set;}
}
Creating a Customer is the essence of the application, so I made that class an AggregateRoot. Because a lot of
times the end user will want to find a customer by its CustomerReference key.
But then again, sometimes the end user wants to search by the name of a Child, to find out the Customer info. Or even sometimes
by the name of an Adult.
I'm not sure if that means that I should make the Child and Adult classes also an AggregateRoot? Or should I always
start searching from the Customer AggregateRoot if I want to search by a Child or Adult name?
No - aggregate root members are only accessible via the aggregate root.
however, If you are wanting to manipulate Adult/Child entities on their own, it is likely you don't need the full Adult and Child entities as part of the customer root. If this is the case replace those collections of entities with collections of Id's and rely on the fully entities to be provided to any functions that require their attributes.
class Customer : AggregateRoot
{
public string CustomerReference {get; private set;}
public string CustomerName {get; private set;}
public string IEnrumerable<AdultId> Adults {get; private set;}
public string IEnrumerable<ChildId> Children {get; private set;}
public void RegisterAnAdult(Adult adult) {...}
public void RegisterAChild(Child child) {...}
}
I emphasised If because this looks a little bit off unless your system is huge and Adult and Child can belong to multiple customers. (How do you handle when an child grows up to transition to an adult?)
As #mgonzalezbaile said, don't model your domain based on queries - searching is a whole different thing - model it on business behavior. (For more info start with [http://www.zankavtaskin.com/2016/06/applied-domain-driven-design-ddd-part-7.html])
Finally, in your example the properties are publicly set-able, if this is on purpose then it might be worth stepping back and re-reading the literature on DDD a few more times, public settable properties potentially allow your entity to move to an invalid state, something that DDD tries to avoid.
Related
I´m trying to understand how to represent certain DDD (Domain Driven Design) rules.
Following the Blue Book convention we have:
The root Entity has global identity and is responsible for checking invariants.
The root entity controls access and cannot be blindsided by changes to its internals.
Transient references to internal members can be passed out for use withing a single operation only.
I´m having a hard time to find the best way to enforce the invariants when clients can have access to internal entities.
This problem of course only happens if the child entity is mutable.
Supose this toy example where you have a Car with four Tire(s). I want to track the usage of each Tire idependently.
Clearly Car is a Aggregate Root and Tire is an Child Entity.
Business Rule: Milage cannot be added to to a single Tire. Milage can only be added to all 4 tires, when attached to a Car
A naive implementation would be:
public class Tire
{
public double Milage { get; private set; }
public DateTime PurchaseDate { get; set; }
public string ID { get; set; }
public void AddMilage(double milage) => Milage += milage;
}
public class Car
{
public Tire FrontLefTire { get; private set; }
public Tire FrontRightTire { get; private set; }
public Tire RearLeftTire { get; private set; }
public Tire RearRightTire { get; private set; }
public void AddMilage (double milage)
{
FrontLefTire.AddMilage(milage);
FrontRightTire.AddMilage(milage);
RearLeftTire.AddMilage(milage);
RearRightTire.AddMilage(milage);
}
public void RotateTires()
{
var oldFrontLefTire = FrontLefTire;
var oldFrontRightTire = FrontRightTire;
var oldRearLeftTire = RearLeftTire;
var oldRearRightTire = RearRightTire;
RearRightTire = oldFrontLefTire;
FrontRightTire = oldRearRightTire;
RearLeftTire = oldFrontRightTire;
FrontLefTire = oldRearLeftTire;
}
//...
}
But the Tire.AddMilage method is public, meaning any service could do something like this:
Car car = new Car(); //...
// Adds Milage to all tires, respecting invariants - OK
car.AddMilage(200);
//corrupt access to front tire, change milage of single tire on car
//violating business rules - ERROR
car.FrontLefTire.AddMilage(200);
Possible solutions that crossed my mind:
Create events on Tire to validate the change, and implement it on Car
Make Car a factory of Tire, passing a TireState on its contructor, and holding a reference to it.
But I feel there should be an easier way to do this.
What do you think ?
Transient references to internal members can be passed out for use withing a single operation only.
In the years since the blue book was written, this practice has changed; passing out references to internal members that support mutating operations is Not Done.
A way to think of this is to take the Aggregate API (which currently supports both queries and commands), and split that API into two (or more) interfaces; one which supports the command operations, and another that supports the queries.
The command operations still follow the usual pattern, providing a path by which the application can ask the aggregate to change itself.
The query operations return interfaces that include no mutating operations, neither directly, nor by proxy.
root.getA() // returns an A API with no mutation operations
root.getA().getB() // returns a B API with no mutation operations
Queries are queries all the way down.
In most cases, you can avoid querying entities altogether; but instead return values that represent the current state of the entity.
Another reason to avoid sharing child entities is that, for the most part, the choice to model that part of the aggregate as a separate entity is a decision that you might want to change in the domain model. By exposing the entity in the API, you are creating coupling between that implementation choice and consumers of the API.
(One way of thinking of this: the Car aggregate isn't a "car", it's a "document" that describes a "car". The API is supposed to insulate the application from the specific details of the document.)
There should be no getters for the Tires.
Getters get you in trouble. Removing the getters is not just a matter of DDD Aggregte Roots, but a matter of OO, Law of Demeter, etc.
Think about why you would need the Tires from a Car and move that functionality into the Car itself.
I'm designing a fairly complex hosted web app that needs to support multiple "Teams" that are effectively isolated from each other. For example, the tables People, Areas, Reports, etc. will have intermingled data populated by the teams at Corporation A, B, C, and on down the line, and the user from Corporation A has logged in, he should only ever see data relevant to corporation A. My plan is to create a relationship between Team and (nearly) every other type and to use a repository to access all those other types, and always query where TeamId matches the TeamId of the person logged in.
So since I want to have
[ForeignKey("Team")]
public int TeamId { get; set; }
public virtual Team Team { get; set; }
on almost every class, I was thinking it might be nice to put those in an abstract class and inherit those properties:
public abstract class OfTeam {
[ForeignKey("Team")]
public int TeamId { get; set; }
public virtual Team Team { get; set; }
}
public class Person : OfTeam {
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
But, I realize this isn't truly what inheritance is about. So I'd like to know
Will this even work?
Is it a terrible idea?
I misunderstood at first and though you were inheriting team, which would have been a bad idea.
If you ever query db.OfTeam then it will union together every single table that inherits from it, which will perform terribly. Scroll down to see the SQL produced here:
http://weblogs.asp.net/manavi/archive/2011/01/03/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and-choosing-strategy-guidelines.aspx
Otherwise the actual DB structure should be identical to if you simply put TeamId/Team on all of those classes directly.
I personally wouldn't do this because it adds little value and could potentially cause headaches down the road.
Instead you could just have an IOfTeam interface on all those classes if there is a need to interact with them in a generic manner for some reason.
As a side note I've done something similar and usually cache TeamId somewhere easily accessible, such that I can anywhere do CurrentIdentity.TeamId and pass it to a query. This allows methods on repository pattern like GetPeople to apply a where criteria with that filter before returning the IQueryable.
My goal is to use NHibernate schema generation along with Fluent NHibernate's automapper to generate my database. I'm having trouble with what I'll call "unidirectional many-to-many relationships."
Many of my entities have localized resources. A single class might look like this:
public class Something {
public virtual int Id {get; private set;}
public virtual Resource Title {get;set;}
public virtual Resource Description {get;set;}
public virtual IList<Resource> Bullets {get;set;}
}
The Resource class doesn't have any references back; these are entirely unidirectional.
public class Resource {
public virtual int Id {get; private set;}
public virtual IList<LocalizedResource> LocalizedResources {get;set;}
// etc.
}
public class LocalizedResource { //
public virtual int Id {get; private set; }
public virtual string CultureCode {get;set;}
public virtual string Value {get;set;}
public virtual Resource Resource {get;set;}
}
Without the IList<Resource>, everything is generated as I'd want -- Resource ID's are in the Title and Description fields. When I add in the IList though, NHibernate adds the field something_id to the Resource table. I understand why it does this, but in this situation it's not a sustainable approach.
What I want is to create a junction table for the bullets. Something like:
CREATE TABLE SomethingBullet (
Id int NOT NULL PRIMARY KEY IDENTITY(1,1),
Something_Id int NOT NULL,
Resource_Id int NOT NULL
)
This way when I add the other twenty-odd entities into the database I won't end up with a ridiculously wide and sparse Resource table.
How do I instruct the Automapper to treat all IList<Resource> properties this way?
Every many-to-many is in fact composed with one-to-many's in object model. If your relationship doesn't need to be bidirectional, just don't map the second side. The mapping on your mapped side is not affected at all:
HasManyToMany(x => x.Bullets).AsSet();
In this case, NHibernate already knows that it needs to generate the intermediate table.
See also this article for many-to-many tips.
:)
The only way I found to make this work with automapping is by constructing your own custom automapping step and replacing the "native" HasManyToManyStep. It's either that or an override, I'm afraid.
I lifted mine off of Samer Abu Rabie, posted here.
The good news is that Samer's code, so far, seems to work flawlessly with my conventions and whatnots, so, once it was in place, it was completely transparent to everything else in my code.
The bad news is that it costs you the ability to have unidirectional one-to-many relationships, as Samer's code assumes that all x-to-many unidirectional relationships are many-to-many. Depending on your model, this may or may not be a good thing.
Presumably, you could code up a different implementation of ShouldMap that would distinguish between what you want to be many-to-many and what you want to be one-to-many, and everything would then work again. Do note that that would require having two custom steps to replace the native HasManyToManyStep, although, again, Samer's code is a good starting point.
Let us know how it goes. :)
Cheers,
J.
Take this following code from an example HR system. The user has the ability to log an absence and can be of various types including holiday and sickness. This would be a domain model over an ORM such as NHibernate.
public class Absence
{
public long Id {get;set;}
public Employee Employee {get;set;}
public DateTime StartDate {get;set;}
public DateTime EndDate {get;set;}
public virtual void DoSomething()
{ ... }
}
public class Holiday : Absence
{
public string Location {get;set;}
public override void DoSomething()
{ ... }
}
public class Sickness : Absence
{
public bool DoctorsNoteProvided {get;set;}
public override void DoSomething()
{ ... }
}
This is an example - please don't question why location would be required, assume it is a specification.
The user wants to change the type - he thought the employee was off sick but then remembered it was a holiday. Again, you may think this is a bad design but treat it like a requirement - this represents a problem that has come up many times for me.
The problem is that you cannot change the type of an object from Sickness to Absence. Generally, the advice would be to Favour Composition Over Inheritance (Gang of Four) and do this:
public class Absence
{
public long Id {get;set;}
public Employee Employee {get;set;}
public DateTime StartDate {get;set;}
public DateTime EndDate {get;set;}
public AbsenceType Type {get;set;}
public void DoSomething()
{
Type.DoSomething();
}
}
But when I do this, when do the properties specific to Holiday and Sickness go (Location and DoctorsNoteProvided respectively)?
Why do you need to change the type of an object?
You will have some kind of collection of Absences, just replace the item in question.
Conceivably rather than replacing you even keep the original request and mark it as superceded, that might be important for audit trail purposes.
It's not the right place for Composition over Inheritance. Here the inheritance is appropriate. And if you need to change the type of absence just create a new one and delete old.
Hmmm, without knowing more about your requirements, I would say the right design is not to change an Absence object to a Sickness object (or vice versa) but to just delete the one you don't want and create a new one of the type you do. Somewhere you must be maintaining a collection of absences, right?
You are correct that classes don't change.
I would model this by having a type hierarchy for an AbsenceType, or AbsenseReason:
abstract class AbsenseReason {
}
class HolidayAbsenseReason : AbsenseReason {
public string Name { get; }
}
I like this model because now AbsenseReason is a value object and is independent of an employee Absence, which is an entity object. This, as you stated, solves the issue with changing the absence reason. Generally speaking, I would favor this over deleting a record, because there may be many associations to consider as well.
Things to consider:
NHibernate does not support inheritance mappings on components so you will have to provide a custom implementation of IUserType.
Consider storing all the data for the different absence reason sub types together with the record for the employee absence entity. Possibly as XML so that you can have collections, etc.
So try to move all type specific functionality to AbsenceType derivatives. If they require something from parent class Absence, you could pass them its reference. Though I would try to avoid that.
If you manipulated Absence object via base class interface, nothing changes, you can keep your old code. Now, if you manipulated specific derivatives, then you will have to grab AbsenceType object from specific Absence and do all the same things on them - still not much to change. If you had holiday.DoSomething(), now you have holiday.Type.DoSomething().
I have a:
class Garage {
int garageID;
ISet<Car> cars
}
should the cars class have garageID as one of its properties, as in:
class Car {
int carID;
int garageID;
String name;
}
That is how it appears in the database, but wondering if the classes on the many side are supposed to have the foreign key as a property or if the ORM just adds that in when performing the SQL (assuming you can specify it in the mappings file).
In short: No. (and yes the ORM will take care of FK based on your mapping files)
The "Car" table will have the GarageId in it but you should not add it to the Car class.
You can have a bi-directional relationship (although opinions vary on whether these are a good idea).
A bi-directional relationship would make the Car class look like this:
public class Car {
public virtual int Id {get; set;}
public virtual Garage Garage {get; set;} //You can traverse back up to Garage
public virtual string Name {get; set;}
}
If you would like me to post the Fluent/XML maps let me know.