DDD modeling, referencing child of aggregate root? - c#

I am trying to learn DDD. I am modeling a property management domain and I think I have two contexts (subdomains?): a property management context and a resident context.
Let's say I have an aggregate root Apartment, that holds Floorplans and Units. Each Apartment can have many Floorplans, and each Floorplan can have many Units.
public class Apartment : IAggregateRoot // for clarity
{
public int Id { get; }
public Address Address { get; set; }
public ICollection<Floorplan> Floorplans { get; set; }
}
public class Floorplan
{
public int Id { get; }
public int ApartmentId { get; set; }
public string Name { get; set; }
public int Bedrooms { get; set; }
public int Bathrooms { get; set; }
public ICollection<Unit> Units { get; set; }
}
public class Unit
{
public int Id { get; }
public int FloorplanId { get; set; }
public string Number { get; set; }
}
Let's say in the property management context I now introduce a Resident who gets assigned to a Unit. My Unit and Resident class now looks like this:
public class Unit
{
public int Id { get; }
public int FloorplanId { get; set; }
public string Number { get; set; }
public ICollection<Resident> Residents { get; set; }
}
public class Resident // in the property management context
{
public int Id { get; }
public string FirstName { get; set; }
public string LastName { get; set; }
public void UpdateBalance(...);
}
My question is now if I introduce a Resident in the resident context (that can PayRent() or UpdateProfile(), etc) they must have a 1:1 relationship with Resident in the property management context, but I thought I cannot reference a non-aggregate root entity without going all the way through Apartment because a Resident cannot exist without an Apartment.
Is my understanding of aggregate roots incorrect? Is Resident an aggregate root in both contexts? I'm not sure how that would be modeled.

My question is now if I introduce a Resident in the resident context (that can PayRent() or UpdateProfile(), etc) they must have a 1:1 relationship with Resident in the property management context, but I thought I cannot reference a non-aggregate root entity without going all the way through Apartment because a Resident cannot exist without an Apartment.
It depends on your architecture. For the most part, it makes sense to me to have an event outside of your domains that'll be handled by both contexts (flowing through the application service down to the aggregates) and will react by "creating" the appropriate actors (a resident and property managent client?). Ensuring 1:1 here would imply ensuring that all events are handled and handling failures graciously (This sounds like a fun excercise).
All contexts will have a boundary. The boundary will serve as the contexts "interface" to consumers. Any communication between contexts should go through this "interface".
As an example: If your contexts is implemented as a microservice (a REST API), you should only communicate to it by sending HTTP REST commands. This isolation keeps the contexts clean. That is the purpose of having contexts.

Is Resident an aggregate root in both contexts?
No, it is only the aggregate root in the Resident aggregate, in the Resident context. When you remove an Apartment entity it causes deleting all the other entities in the aggregate inclusive the Resident entity (only in the Property Management context). But when a Resident leaves a unit in the apartment it doesn't require to delete any other entity within the Apartment aggregate.
Is my understanding of aggregate roots incorrect?
No, you are right saying
I cannot reference a non-aggregate root entity without going all the
way through
But not only an aggregate root of one aggregate can refer to the root of another aggregate. A non-root entity from one aggregate can reference the aggregate root from another aggregate. Please take a look at the image below.
This image is taken from the Pluralsight course Domain-Driven Design in Practice
For identifying the root entity in aggregate use this principle that is already described in my answer above (the quote is taken from the book Applied Akka Patterns):
Aggregates, and their associated roots, are a tricky concept. It can
be difficult to determine what is an aggregate in your system, or more
importantly, what is the right aggregate root. Generally, aggregate
roots are the top-level pieces of a system. All of your interactions
with the system will in one way or another interface with an aggregate
root (with a few exceptions). So how do you determine what your
aggregate roots are? One simple rule is to consider deletion. If you
pick a specific Entity in the system and delete it, does that delete
other Entities in the system? If your system consists of people who
have addresses, and you delete an address, does it delete other parts
of the system? In this case, probably not. On the other hand, if you
delete a person from the system, there is a good chance that you don’t
need to keep that person’s address around anymore, so in this case, a
person might aggregate an address.
Now your question about how it should be modeled:
My question is now if I introduce a Resident in the Resident context
(that can PayRent() or UpdateProfile(), etc) they must have a 1:1
relationship with Resident in the Property Management context, but I
thought I cannot reference a non-aggregate root entity without going
all the way through Apartment because a Resident cannot exist without
an Apartment.
In my opinion, Resident in the Property Management context should be presented as an entity since it has an ID (e.g. passport, driving license) and the entity must have only those properties from the entity Resident in the Resident context that will be used in the Property Management context.
I would suggest reconsidering the name Resident for the context Resident. When you keep information about a person but this person is not currently living in an apartment he\she is not technically Resident of this apartment, it is just a person that is planning\planned to live, currently lives, or lived in the apartment. I think, the better name for what you call the Resident context is Person.
For communication between the contexts use integration events (don't confuse them with domain events):
Domain events versus integration events
Semantically, domain and
integration events are the same thing: notifications about something
that just happened. However, their implementation must be different.
Domain events are just messages pushed to a domain event dispatcher,
which could be implemented as an in-memory mediator based on an IoC
container or any other method.
On the other hand, the purpose of integration events is to propagate
committed transactions and updates to additional subsystems, whether
they are other microservices, Bounded Contexts or even external
applications. Hence, they should occur only if the entity is
successfully persisted, otherwise it's as if the entire operation
never happened.
As mentioned before, integration events must be based on asynchronous
communication between multiple microservices (other Bounded Contexts)
or even external systems/applications.
Thus, the event bus interface needs some infrastructure that allows
inter-process and distributed communication between potentially remote
services. It can be based on a commercial service bus, queues, a
shared database used as a mailbox, or any other distributed and
ideally push based messaging system.
Domain events: design and implementation
I have noticed that this part of your question:
I am trying to learn DDD. I am modeling a property management domain
and I think I have two contexts (subdomains?)
sounds like you are not sure about the meaning of terms context and subdomain. Please take a look at the image below; it is quite self-explanatory:
This image is taken from the Pluralsight course Modern Software Architecture: Domain Models, CQRS, and Event Sourcing
A sub-domain represents a part of a problem, whereas a bounded context represents a part of a solution that solves the problem. Each sub-domain usually covered by one bounded context. In some cases, one sub-domain may correspond to more than one bounded context, e.g. when you have a sub-domain with old requirements and a bounded context that already implemented these requirements, and later you have new requirements and you don't want to change the existing bounded context for some reason, then you may introduce the new bounded context for these new requirements. This new context should be separated via anti-corruption layer from the old one.

Related

It is possible to use child class to implement Separation of concerns using EF Core?

My goal is async loading of related entities using DBContext.
Let imagine two projects. The first named MyApp.Domain and contains domain entities.
namespace MyApp.Domain
{
public class PlanPage
{
public Guid Id { get; set; }
}
}
namespace MyApp.Domain
{
public class PlanPageDay
{
public Guid Id { get; set; }
public Guid PlanPageId { get; set; }
}
}
The second project named MyApp.Infrastructure.EntityFramework and contains configuration of projection entities to database. It also contains class which extends domain entity and implements Entity framework specific logic.
namespace MyApp.Infrastructure.EntityFramework.Models
{
public class PlanPageEntity : PlanPage
{
private readonly ApplicationDbContext _applicationDbContext;
protected PlanPageEntity(ApplicationDbContext applicationDbContext)
{
_applicationDbContext = applicationDbContext;
}
public ICollection<PlanPageDay>? Days { get; set; }
public async Task<ICollection<PlanPageDay>> GetDays()
{
return Days ??= await _applicationDbContext.PlanPageDays
.Where(pd => pd.PlanPageId == Id)
.ToListAsync();
}
}
}
The purpose of this example is simple. We separate infrastructure code from domain code. Look how do we plan to use this concept:
// Entity initializing code. Placing somewhere in domain logic.
var plan = new PlanPage(/*some constructor arguments*/);
// Entity loading code. Placing somewhere in infrastructure implementation.
public async Task<PlanPage> GetPlanPage(Guid id)
{
return await _applicationDbContext.Set<PlanPageEntity>().FindAsync(id);
}
Note that we tell to Entity framework to use child class (PlanPageEntity) so it can handle all specific things that it can.
The question is: Is it possible to configure the EF so that it allows us to use this concept?
As requested here's a little more details for my opinion stated in the comments.
The main reason why I think your current approach is a bad idea is that it violates the separation of concerns design principle: when you are mixing domain models with data access models, you make your domain logic completely dependent on how you model the data in your database. This quickly limits your options because the database may have some restrictions on how you can model your data that doesn't fit well with the domain logic you want to implement as well as making maintenance difficult. E.g. if you decide to split up one DB table into two then you might have a big task ahead of you in order to make your domain logic work with those two new models/tables. Additionally, making performance optimizations in your database easily becomes a nightmare if not thought through ahead of time - and you shouldn't spend time thinking of optimizing your system before it's necessary.
I know this is a little abstract since I don't know much about your domain but I'm sure I could find more arguments against it.
Instead, separating data access models (and in general all external data models) from your domain models makes it much easier to maintain: if you need to make some changes to your database, you simply need to update the logic that maps the data from your data access models to your domain model - nothing in your domain logic needs to change.
In the examples you have given, you have already logically separated your domain models and data access models into two separate projects. So why not follow through with that thought and separate the two with a binding/mapping layer in-between?
Is it possible to configure the EF so that it allows us to use this concept?
Yes. Essentially you have DTO's, and your Entities derive from your DTOs. So when you fetch an Entity you can return it directly. But if you wouldn't be able to attach a non-Entity, so you'd have to map it. It's going to be inconvenient, and like 99.999% of bespoke entity and repository designs, will be ultimately a waste of time.
This is somewhat similar to the what EF already does for you. Start with persistence-ignorant Entity classes, and introduce persistence-aware runtime subtypes for scenarios that require them, which is basically just Lazy Loading.

How do I use the UserManager from project A in project B?

Both project A and project B are ASP NET Core 2.2 apps.
Project B uses Hangfire for background jobs and does very little else, and the fact that it uses Hangfire may not even be important (more on this at the bottom). Project A enqueues jobs on B's Hangfire.
Now, let's say I have my class representing a task, called Job. This is contained in project C, a plain old class library referenced by project B, and which in turns references other projects containing the entities it's working with.
Dependencies are to be injected into this class through the constructor:
public class Job
{
public Job(UserManager<ApplicationUser> userManager,
IThisRepository thisRepository,
IThatRepository thatRepository)
{
}
public void Execute(string userId)
{
// this is where the work gets done
}
}
and for the most part they do get injected: IThisRepository and IThatRepository are injected and they work... mostly.
In project B's Startup.cs, the one that is supposed to run this job, I manually and successfully registered those interfaces, along with the DbContext that they require a some other stuff.
UserManager was quite a bit harder to register manually because of all the parameters its constructor requires, so since I didn't really need it inside my job, I just decided to make a few changes.
Now, an example of the entities I'm working with is as follows:
public class Category
{
[Key]
public int Id { get; set; }
// several other properties of primitive types
public ApplicationUser User { get; set; }
[Required]
public string UserId { get; set; }
}
public class Dish
{
[Key]
public int Id { get; set; }
// several other properties of primitive types
public ApplicationUser User { get; set; }
[Required]
public string UserId { get; set; }
public Category Category { get; set; }
[Required]
public string CategoryId { get; set; }
}
now the problem is this: inside of Job I try to create a new Dish and associate it with both the user and the category. Since I just have the user id and I don't have access to UserManager, this is what I try to do:
// ...
var category = await categoryRepository.FindByUserAndCode(userId, "ABC");
// this is a category that is guaranteed to exist
var dish = new Dish();
dish.UserId = userId;
// notice there's no dish.User assignment, because I don't have an ApplicationUser object
dish.Category = category;
dishRepository.Upsert(dish); (which internally either creates a new entity or updates the existing one as appropriate)
and this is where it all breaks down, because it says that a category with the same Id I'm trying to insert is already present, so I'm trying to duplicate a primary key.
Since the category with code ABC for this user exists in the db, I thought it was odd.
Here's the thing: the instance of Category that the repository returns does have it's UserId property populated, but the User property is null.
I think this is what causes my problem: EF probably sees that the property is null and considers this object a new one.
I don't know why it comes up null (and it does even for other entities that all have a property referencing the user), but I tried to backtrack and, instead of using just the user id, I wanted to try to get Hangfire to instantiate Job injecting UserManager<ApplicationUser> into it, so at least I could get an instance of my user by its id.
It's worth noting that this works in other parts of project A, it's just that when I'm executing the background job something goes horribly wrong and I can't for the life of me figure out what it is.
However the dependencies of UserManager are many, and I fear I might be barking up the wrong tree or doing it completely wrong.
I said that the fact I'm using Hangfire might not matter because the assumption under which it operates is: just give me the name of your class, I'll take care of instantiating it as long as all the dependencies have been registered.
Anyone has done this before and can help shed some light?
You've included an absolute ton of information here that is entirely inconsequential to the problem at hand. What your issue boils down is simply the exception you're getting when attempting to add a dish: "a category with the same Id I'm trying to insert is already present, so I'm trying to duplicate a primary key."
This is most normally caused by attempting to use a detached entity as a relationship, i.e.:
dish.Category = category;
If category is detached from the context, then EF will attempt to create it because of this assignment, and since it already exists, that creation fails. We can't see what's going on in categoryRepository.FindByUserAndCode, but I'd imagine you're either calling AsNoTracking with the query, or are newing up an instance of Category manually yourself. In either case, that instance, then, is detached from the context. To attach it again, you simply need to do:
context.Attach(category);
However, you don't have direct access to your context here. This is yet one more reason that you should never use the repository pattern with EF. So much pain and suffering has been subjected on developers throughout the year by either bad advice or erroneously attempting to do things as they are used to.
EF is an ORM (object relational mapper), which is a fancy way of saying that it is itself a data layer. The DbContext is the unit of work and each DbSet is a repository... already. The repository pattern is for abstracting low-level database access (i.e. all the crud of constructing SQL strings, for example). EF is already a high-level abstraction, trying to cram it into another repository pattern layer only cripples it and leads to problems like what you're experiencing here.
Long and short, the issue is that category is detached. You need to either ensure that it never becomes detached in the first place (i.e. don't use AsNoTracking for example) or find a way to ensure that it's reattached later. However, your best bet here is to throw away all this repository garbage completely and just use the context directly. Choosing to use an ORM like EF is simply choosing to use a third-party DAL, rather than write your own. Writing your own, anyways, on top of that is just wrong. You use the built in routing framework in ASP.NET Core. You use the built in templating engine (i.e. Razor). Do you feel the need to put some abstraction around those? Of course not, so why is a DAL any different? If you simply must create an abstraction, then use a meaningful one such as CQRS, service layer, or microservices patterns.

DDD - POCOs. First step

It is my first time in DDD. In company we don't have "domain master". I have only read about DDD I need to implement domain with DDD aproach.
So, I know that in domain there are no place for Database features. But if I would use my domain with Entity Framework and NOSQL database. With EF i need to make collections virtual and in constructor alloce as new. This is bad in DDD?
My code:
public abstract class Merchant : AggregateRoot
{
public Company Company { get; set; } // Entity
public string CIF { get; set; }
public string NIP { get; set; }
public string Status { get; set; }
public Address Address { get; set; } // Entity
public Group Group { get; set; } // Entity
public virtual ICollection<Brand> Brands { get; set; } // Brand is entity
protected Merchant()
{
this.Brands = new List<Brand>();
}
}
There are multiple shades of opinion about that issue in the DDD space.
To me, the primary measure of "persistence ignorance" is :
Will a change in my database break things in my domain layer, forcing
me to open up the domain model and modify stuff to fix it ?
If we look at your example, the answer is clearly no.
It would have been the case if you had for example data annotations in your entity class referring to table or column names, or if you relied on mapping by convention and changed the Merchant table name to Reseller in the DB. But having a default constructor and virtual property doesn't make your domain class more fragile in the face of database changes.
Then you have a secondary question, a less critical one IMO :
Is the ORM a hindrance in my implementing domain entities just the way I
want and as DDD-compliant as they need to be ?
This one is a bit more challenged. It might be, if the ORM forces you to add operations that can leave the domain object in an inconsistent state. I wouldn't consider a parameterless constructor as prone to that though, since it can be private and thus impossible to shoot yourself in the foot with. Same with setters.
Some consider that small traces such as the need for virtual and parameterless constructor violate DDD, because your entities are not pure any more, they contain oddities caused by the presence of an ORM. Therefore, you should create a second "persistence" model to leave the domain model untainted. I don't. I think most of the time it's not worth the tradeoff in terms of complexity - you can live with the small quirks as long as the first rule of persistence ignorance holds.
I would be more concerned about having public setters than a protected default constructor or a virtual property. The problem with that is can lead to an inconsistent state of the entity. For example, you may want to validate the address properties to make sure all the required properties are set and the postal code corresponds to the state/country. Another example would be status transitions; once the entity reaches a "final" status, it cannot be changed anymore.
While you can create separate validators for entities and use them before you persist the entities, it defeats the purpose of a rich domain model.
There are a few ways to get around it. You can create DTO objects that mirror the database schema and use hydrators to populate the entities (with protected/internal property setters) from those DTOs assuming the data in the database is always in the consistent state. All the new changes will have to go through entity methods to get validated. Then you would hydrate the DTOs based on the latest entity data and persist it.
CQRS with event sourcing is a more advanced alternative of this that persists all changes as an immutable log/event-store rather than (only) the latest data snapshot. But that is not something that is necessary for every domain scenario.

Designing a Persistence Layer

For a project we are starting to look at persistence features and how we want to implement this. Currently we are looking at keeping Clean Architecture in mind, probably going for Onion Architecture. As such, we want to define a new outer layer which in which the persistence layer resides.
We're looking at various ORM solutions (we seem to be converging to Entity Framework) using SQLite as data store and we are hitting a snag: How should be manage ID's and deal with add/removal in some collection or move some instance between different collections.
In the core of our 'onion', we want to keep our POCO objects. As such, we do not want some kind of 'ID' property to be added in our business objects. Only inside the persistence layer do we want to have classes with object ID's. Because of this separation:
how should removing a business object from some collection cause a row to be deleted from the SQLite database?
More complex (at least I think it is), how should a POCO instance moved from 1 collection to another cause a foreign key of a SQLite databaserow to be changed? (Instead of removing the row and recreating it with the same values)
Looking around the internet I've yet to find an implementation somewhere that demonstrates a persistence layer in a Clean Architecture design. Plenty of high level diagrams and "depend only inward", but no source code examples to give a demonstration.
Some possible solutions that we came up with so far:
Have some lookup between POCO instances and their representative 'database model objects' (which have ID's etc) within the persistence layer. When saving the project state, business model objects will be matched with this database model objects and update the state for the matches accordingly. Then the object is persisted.
When loading a project, the persistence layer returns decorator objects of business objects that add an ID to the business object, which is only visible within the persistence layer by casting the objects to that decorator class. However, this prevents us from defining sealed POCO objects and seems to break the Clean Architecture design philosophy.
Option 1 seems costly in memory due to effectively doubling the business objects in memory. Option 2 seems the most elegant, but as I've written: it feels that it breaks Clean Architecture.
Are there better alternatives to there? Should we just go for Option 2 and take Clean Architecture more as guidelines than rule? Can someone point us to a working example in code (I did find a iOs example at https://github.com/luisobo/clean-architecture, but as I'm not literate in the language it cannot do much with it).
As others have mentioned in the comments, IDs are a natural part of applications and are usually required in other parts than persistence. So trying to avoid IDs at all costs is going to produce awkward designs.
Identity Design
However, identity design (where to use which IDs, what information to put in IDs, user defined vs system generated, etc.) is something that is very important and requires thought.
A good starting point to determine what requires an ID and what not is the Value Object / Entity distinction of domain-driven design.
Value objects are things that consist of other values and don't change - so you don't need an ID.
Entities have a lifecycle and change over time. So their value alone is not enough to identify them - they need an explicit ID.
As you see here, reasoning is very different from the technical point of view that you take in your question. This does not mean you should ignore constraints imposed by frameworks (e.g. entity framework), however.
If you want an in-depth discussion about identity design, I can recommend "Implementing DDD" by Vaughn Vernon (Section "Unique Identity" in Chapter 5 - Entities).
Note: I don't mean to recommend that you use DDD because of this. I just think that DDD has some nice guidelines about ID design. Whether or not to use DDD in this project is an entirely different question.
First of all, everything in the real world have ids. You have your social security number. Cars have their registration number. Items in shops have an EAN code (and a production identity). Without ids nothing in the world would work (a bit exaggerated, but hopefully you get my point).
It's the same with applications.
If your business objects do not have any natural keys (like a social security number) you MUST have a way to identify them. You application will otherwise fail as soon as you copy your object or transfer it over the process boundry. Because then it's a new object. It's like when you cloned the sheep Dolly. Is it the same sheep? No, it's Mini-Dolly.
The other part is that when you build complex structures you are violating the law of Demeter. For instance like:
public class ForumPost
{
public int Id { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public User Creator { get; set; }
}
public class User
{
public string Id { get; set; }
public string FirstName { get; set; }
}
When you use that code and invoke:
post.User.FirstName = "Arnold";
postRepos.Update(post);
what do you expect to happen? Should your forum post repos suddenly be responsible of changes made in the user?
That's why ORMs are so sucky. They violate good architecture.
Back to ids. A good design is instead to use a user id. Because then we do not break law of Demeter and still got a good separation of concern.
public class ForumPost
{
public int Id { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public int CreatorId { get; set; }
}
So the conclusion is:
Do not abandon ids, as it introduces complexity when trying to identify the real object from all the copies of it that you will get.
Using ids when referencing different entities helps you keep a good design with distinct responsibilities.

How To Model Aggregates and Persist to Database in DDD

I am just trying to get out of my comfort zone of typical N-Tier architecture of Repository/Service/Presentation and have started looking at DDD with Aggregates and I have to admit I'm a little confused and was hoping someone could clarify the following example:
If I had an Entity called News, NewsImage and Customer which were all EF persist-able objects like so:
public class Customer
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class NewsImage
{
public virtual int Id { get; set; }
public virtual byte[] Data { get; set; }
public virtual News News { get; set; }
}
public class News
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<NewsImage> NewsImages { get; set; }
public virtual Customer Customer { get; set; }
}
As I understand it these could be the objects we would use to persist the domain objects to the database but if we are using aggregates from the domain model we could have something like this:
public class NewsAggregate
{
public int Id { get; set; }
public string Name { get; set }
public void AddImageToNews(byte[] imageData)
{
// Hide NewsImage or that object and add the byte[] data here?
}
}
My questions are following and I would appreciate any clarification as I am certain I am misunderstanding the fundamental principles here:
Only the aggregate objects should be exposed to the presentation layer (or any consuming layer).
How do I handle converting/persisting the aggregate objects to the database, I could use mapping which is fine but then how do I know if I am creating an object or updating (by whether it is transient if the Id is set or not?). How do I know if new images have been added and which to update or remove? I think the problem I am having is I call create pass a news aggregate to a Repository and create it, I could then get the aggregate back from the domain populated via the entities with EF and then add an image, when I pass the news aggregate back how do I know what has changed in order to create/update data?
Where should the customer go, should it be on the news aggregate object as an AddCustomer method, should there be a CustomerAggregate which has an AddNews method and with both of these options how to persist?
Many thanks for any insight, I've been reading around and looking at sample projects which demonstrate the concept but don't seem to fully explain best ways to achieve this.
First: DDD does not suggest you any specific architecture. I've used many different architectures with DDD and you should use what's good for the task. Obviously, if you think in a data driven way, you will encounter many problems with DDD.
DDD is a methodology designed to cope with complex business rules. You should not use it if your application value is in technological asset (as being in the cloud, exposing web services or some nice html5/mobile UI), but in the complexity of the business that it handles.
You should not use DDD for simple business rules. The rule of thumbs is: if you don't need a domain expert to understand the business, you don't need DDD at all.
Then, to properly understand aggregates, you should read the Vernon's essay on the topic.
That essay explain that aggregates exist to ensure business invariants.
You should never use aggregates just to optimize db access.
1) It depends on what capacity. There is a rule stating that aggregates can only reference other aggregates directly - not entities or value objects contained in other aggregates. This is to enforce aggregates as consistency boundaries - they fully encapsulate what they "aggregate". There should be a repository per aggregate. The presentation layer, and any outer layer, can require references to aggregates in two general capacities - for display purposes or for behavioral purposes. An aggregate shouldn't concern itself too much with how it will be displayed because queries can be implemented using a different model better suited for the task - a read-model. Instead, the aggregate should focus on behavior. And yes, in cases where the presentation layer wishes to execute a behavior on an aggregate it should reference the aggregate by its identity. Better yet, create an application service to encapsulate the domain layer and expose the behaviors as a simple facade.
Also, an aggregate is not a single class but usually a set of classes clustered around an aggregate root which is an entity. You don't necessarily need a separate class to represent the aggregate, it could just be the root entity.
2) For persistence, it seems you're using EF which should handle all change tracking for you. It should keep track of which objects are persistent or which are transient. ORMs such as NHibernate also do this.
2.1) This depends on whether Customer is itself an aggregate. If so, then News should reference Customer by ID only. Moreover, it may be that a customer is required for a news entity in which case a customer ID should be passed to the constructor of the News entity. If it is not required, then there is a behavior which associated a customer with a news entity. Consider this from the domain perspective - what is the meaning of associating a customer with a news entity? Try to move away from thinking in a technical, CRUD manner such as AddCustomer and think more in terms of the surrounding business intent.
As pointed out by Giacomo Tesio, DDD shows its value in domains with some complexity in business logic. If all your behaviors can be mapped to CRUD then leave it CRUD. Otherwise, look for behaviors in your domain instead of focusing on the data. Your entities and value objects should expose behaviors and hide state as much as possible. Do read and re-read the referenced article: Effetive Aggregate Design by Vaughn Vernon.

Categories

Resources