I am working on an events ticketing system and I am trying to use DDD. However, I am unsure about how to model some of my aggregates.
I have the main Event aggregate:
public class Event : Entity<Guid>, IAggregateRoot
{
public string Name { get; private set; }
public Organizer Organizer { get; private set; }
public Venue Venue { get; private set; }
public DateTime StartsAt { get; private set; }
public short MinAge { get; private set; }
public bool IsAvailable { get; private set; }
public EventType Type { get; private set; }
//constructor and mehtods
}
and also have the Venue and Organizer Aggregates:
public class Venue : Entity<Guid>, IAggregateRoot
{
public string Street { get; }
public Venue(Guid id, string street) : base(id)
{
Street = street;
}
}
public class Organizer : Entity<Guid>, IAggregateRoot
{
public Organizer(Guid id) : base(id)
{
}
}
My questions are:
I have different services that handle creation and other operations for the Venues and Organizers. The Events service is consuming kafka messages from the other two services and persists the venues and organizers in its own database. I would like to mention that the Venues and Organizers services have a lot more information about their respective entities than the Events service, so it is not a 100% data duplication. Is this the right way to share data between different services?
In the events service, should the Organizer and Venue be considered an aggregate or an entity? Neither of those is accessed on itss own in the context of the Event service.
How should I handle persisting and retrieving entities from the database?
An Entity is something that has an own entity, an unique identifier, that has significance.
You use an aggregate when you have entities (and also value objects) with a strong dependency and has sense manage all of them like a single object. In this form, outside you work with some entity (the aggregate root) that manage all the aggregates entities.
With an example is easier to understand. Suppose you have Invoice entity and InvoiceLine entity. Both of them are important, has a unique identifier... and you may work with them as entities. You have a table in the database for invoices and for the lines. Working with the entities as is, you must control some things like, for example, the total of the invoice. When in any place you change the price of a line, you need have near the invoice, to update the total. It's a very simple example but in more complex scenaries, this kind of things ends with wrong data because in some place, you forget update some related data.
So, it's interesting have and aggregate root that contains this two aggregates and all about them are encapsulated in the root aggregate. You update line price through the aggregate root and root update the total of the invoice. Each entity have a reference to the root.
Usually, the aggregate root has a repository to manage the data of all their aggregates. Entity Framework differ a bit in this point, having a repository per entity.
Related
I have a lack of understanding of the DDD aggregate topic.
I do have an Offer aggregate that has navigation property to its children's collection OfferProducts.
When I learned entity framework I thought I should always define navigation properties on both sides of the relation but Ardalis (maintainer of Specification package for ef https://github.com/ardalis/Specification) wrote somewhere these words which I do not understand correctly:
You want to avoid having navigation properties that span Aggregates.
So you need to decide where navigation properties should go, and where
non-navigation key properties should go instead.
This is how I designed my entities:
public class Offer : BaseEntity, IAggregateRoot
{
...
public ICollection<OfferProduct> OfferProducts { get; private set; } = new List<OfferProduct>();
public Guid InquiryId { get; private set; }
public virtual Inquiry Inquiry { get; private set; } = default!;
}
public class OfferProduct : BaseEntity, IAggregateRoot
{
...
public Guid OfferId { get; private set; }
public virtual Offer Offer { get; private set; } = default!;
public Guid InquiryProductId { get; private set; }
public virtual InquiryProduct InquiryProduct { get; private set; } = default!;
}
public class Inquiry : BaseEntity, IAggregateRoot
{
...
public ICollection<Offer> Offers { get; private set; } = new List<Offer>();
public ICollection<InquiryProduct> Products { get; private set; } = new List<InquiryProduct>();
}
public class InquiryProduct : BaseEntity, IAggregateRoot
{
...
public Guid InquiryId { get; private set; }
public virtual Inquiry Inquiry { get; private set; } = default!;
public ICollection<OfferProduct> OfferProducts { get; private set; } = new List<OfferProduct>();
}
Ardalis is saying that navigation properties should be defined only on one side.
I do not know if it is because of some DDD principles or maybe because it has some performance drawbacks?
Repository from your Ardalis specification package only works with aggregate root.
OfferProduct entities are created only with the Offer entity and are never updated.
InquiryProduct entities are created only with the Inquiry entity and are never updated.
I have a business use case where I need to fetch OfferProducts not only belonging to one Offer but filtered by InquiryProductId so I thought the easiest way will be to mark the OfferProduct entity with IAggregateRoot interface and query it from the repository directly. But I think it's cheating and it's not correct because if I understand correctly AggregateRoot should be the only one and I should always query from the root.
I could fetch it from the Inquiry aggregate root but then my specification would have to be that complex:
public class InquiryProductOffersSpec : Specification<Inquiry, InquiryDetailsDto>, ISingleResultSpecification
{
public InquiryProductOffersSpec(Guid inquiryId, Guid productId) =>
Query
.Where(i => i.Id == inquiryId)
.Include(i => i.Products.Where(ip => ip.Id == productId))
.ThenInclude(ip => ip.OfferProducts);
}
This probably would be more correct from the DDD perspective but the query will be less performant than simple select * from OfferProducts where inquiryProductId = 'someId'
So my questions are:
should I remove IAggregateRoot from InquiryProduct and OfferProduct entities and fetch only from the Inquiry entity?
why it is better to keep navigation properties only on one side of the relation?
maybe my entities and relations are designed incorrectly and that's why I am struggling with that complex query?
I will introduce the operation of the system:
The system can create inquiries with its InquiryProducts, then there can be offers created for each inquiry and each offer can have some OfferProducts related to the InquiryProduct.
When writing it thought came to my mind that maybe the only AggregateRoot should be the Inquiry entity as any of the other entities can't exist without Inquiry. But In the system, I also need to fetch(search) offers independently of inquiry and I couldn't do it if I won't mark Offer with an IAggregateRoot interface.
should I remove IAggregateRoot from InquiryProduct and OfferProduct entities and fetch only from the Inquiry entity?
Yes. The whole point of an aggregate root is to organize entities into top-level entities responsible for their dependents which don't really make sense to query on their own.
why it is better to keep navigation properties only on one side of the relation?
Bi-directional references should only be used when there is a clear benefit to having them. Otherwise they just lead to having multiple pathways to get to information that can either result in expensive, unexpected lazy load calls or "broken" links if Lazy Loading is disabled.
For example, a relationship between something like a Customer and Order can make sense to treat both as aggregate roots. There will be a arguable value to get information about Orders for a particular customer, and value in getting information about a Customer from a given Order. Versus scenarios like relationships like Orders and Users (Created By/Modified By) or Orders/Customers and Addresses. An Order benefits from being able to access information about a User that created or last modified it, or Address details, but it doesn't make much sense to bother tracking what Orders a user Created/Modified, or what Order a given Address might be associated with.
You can still query this information if needed through the aggregate root without relying on bi-directional references. For instance if I do happen to care about what orders a particular user did modify, I don't need the structural overhead and "mess" of:
var orders = currentUser.OrdersICreated;
// or
var orders = currentUser.OrdersIModified;
Since most entities in a system might track something like a CreatedBy/ModifiedBy reference back to a User, it would be ridiculous to start putting bi-directional references to every collection of entities in the User entity.
Where these aren't bi-directional references... I can instead use the aggregate root if and when there is a need:
var ordersQuery = _context.Orders.Where(x => x.CreatedBy.UserId == currentUserId);
The problem with relying on bi-directional references is that you end up doing a lot of processing in-memory, which is expensive from a memory standpoint, as well as you end up dealing with potentially stale data over time. In the above example, going back to build queries rather than relying on navigation properties means that I can leverage projection to get back just the details I might need, which could be something as simple as a .Any() check or a .Count().
My advice when it comes to getting the most out of EF is to adapt to leverage its querying and projection to build efficient queries, then deal with aggregate roots solely when you actually need to work with a complete picture of ideally a single entity and it's related details.
Take a look at the following UI:
I am allowing the user, who owns an auto shop of some kind, to select what types of service his shop provides. There are 5 levels to my hierarchy and thousands of total entries. Selecting (checking) any skill area automatically selects all sub-areas or child areas. Each area has an ID which for the top level looks like 10000, the next level 11000, etc...
My questions:
How can I achieve this UI with one code base supporting mobile, tablet and desktop interfaces?
How can I represent the hierarchy using Entity Framework for populating the hierarchy as well as storing the user's selections?
The application is in ASP.Net MVC 4 using SimpleMembership.
The best way to have one code base supporting multiple platforms is to use ASP.NET MVC 4 WebAPI (JSON or XML) as a REST web service. You can find more about it here: http://www.asp.net/web-api
There are also a couple of ready-to-use parsers to deserialize the JSON/XML data into C# object on the client side.
Second question seems to be more related to the database schema behind the Entity Framework abstraction. In terms of EF probably the best way to organize your data is to have categories referencing other categories with the last category referencing the actual services. Are you familiar with the concept of database relations, foreign keys, etc?
Edit:
public class Category1{
public string Name { get; set; }
public virtual ICollection<Item> Items { get; set; }
}
public class Category2{
public string Name { get; set; }
public Category1 ParentCategory { get; set; }
public virtual ICollection<Item> Items { get; set; }
}
public class Item{
public string Name { get; set; }
public decimal Price { get; set; }
}
This is an example how would you write code-first EntityFramework objects. Category2 has a parent of type Category1 and both categories contain a collection of items. Pluralsight has an excellent course on EF code first which covers all the basics.
From what I have read POCO classes should be persistence ignorant and should not contain references to repositories.
Q1. Given the above, how would I populate the QuestionBlocks collection? I have read that POCO's should contain behavior so you don't end of with an anemic model, so I'm kind of confused as how one is supposed to do that without persistence. If that's the case then what kind of behavior would you put in a POCO?
Ex:
public class Survey
{
public int SurveyId { get; set; }
public string Title { get; set; }
public int BrandId { get; set; }
public DateTime Created { get; set; }
public List<SurveyQuestionBlock> QuestionBlocks { get; set; }
[ResultColumn]
public string Name { get; set; }
/// <summary>
/// Constructor
/// </summary>
public Survey()
{
Created = DateTime.Now;
QuestionBlocks = new List<SurveyQuestionBlock>();
}
}
I would append another view: POCO states for objects which are not dependent on any framework. The wiki definition of a POJO is much more meaningful to me then the one for POCO:
http://en.wikipedia.org/wiki/Plain_Old_Java_Object
To paraphrase the wiki definition of the POJO, we can say that POCO object might not be forced to:
I. Extend prespecified class:
public class MyClass : AnyFramework.ObjectBase {...
II. Implement prespecified interfaces
public class MyClass : AnyFramework.IHaveDependency {...
III. Contain prespecified attribute
[AnyFramework.KeyAttribute]
public class MyClass {...
Given this (almost anything else is allowed) in the meaning of taking care about the object state. Other words, if object will check Business logic, it is correct.
But any POCO object can be used in a framework. Today it is mostly for ORM which is responsible for persistence. All application tiers are working with POCO objects, while data layer is responsible for loading and persisting (CRUD). This is mostly done via Proxies of these POCO objects.
So, POCO could be used as full business object, which can take care about itself (check correctness of collection items, properties...). This makes it different from DTO
Given the above, how would I populate the QuestionBlocks collection?
When reading from a database, the persistence infrastructure should populate the QuestionBlocks collection - reconstitution. Reconstruction should not invoke behavior, it should only set appropriate fields on the POCO. This is the responsibility of the repository. A repository is typically referenced from an application service, which sets up the stage for invoking entity behavior.
If that's the case then what kind of behavior would you put in a POCO?
The behavior in the POCO entity should be concerned with making changes to the entity itself as well as maintaining invariants - ie ensuring the integrity of the entity. In your example, the simplest kind of behavior on the POCO should be method for adding a new question block to the collection on the survey. Ideally, you would make many of the properties on the survey entity read-only:
public class Survey
{
public int SurveyId { get; private set; }
public string Title { get; private set; }
public int BrandId { get; private set; }
public DateTime Created { get; private set; }
public IList<SurveyQuestionBlock> QuestionBlocks { get; private set; }
public string Name { get; private set; }
public void AddQuestionBlock(string questionBlockInfo)
{
this.QuestionBlocks.Add(new SurveyQuestionBlock(...));
}
public Survey()
{
Created = DateTime.Now;
QuestionBlocks = new List<SurveyQuestionBlock>();
}
}
The persistence layer should be able to set the values of the read-only properties via reflection. You can go a step further and only expose the question blocks collection as a read-only collection to ensure that it can only be modified from within the entity itself.
I'm confused on how I'm going to updated related entities using DDD. Let say I have a Employee Class and Workschedule Class. How should I updated a specific workschedule of a certain employee? The relationship between Employee and Workschedule is One-To-Many. Below is the code I'm using how to Add/Update a certain workschedule.
public class Employee
{
public int EmployeeId { get; set; }
public virtual ICollection<WorkSchedule> WorkSchedules { get; set; }
public WorkSchedule AddWorkSchedule(WorkSchedule workSchedule)
{
this.WorkSchedules.Add(workSchedule);
return workSchedule;
}
public WorkSchedule EditWorkSchedule(WorkSchedule workSchedule)
{
var originalWorkSchedule = this.WorkSchedules.FirstOrDefault(w => w.WorkscheduleId == workSchedule.WorkscheduleId);
originalWorkSchedule.ClockIn = workSchedule.ClockIn;
originalWorkSchedule.ClockOut = workSchedule.ClockOut;
return originalWorkSchedule;
}
}
public class WorkSchedule
{
public int WorkScheduleId { get; set; }
public DateTime ClockIn { get; set; }
public DateTime ClockOut { get; set; }
public int EmployeeId { get; set; }
}
Is this correct? Did I follow DDD correctly? Also, my thinking right now Workschedule is a value object but I'm putting and ID for normalization purposes
your Model should be "POCO" class
CRUD methods such.. Add or Edit will be considored as part of "Service" or "Repository"
here is a quick idea that just came to my mind / how should it look like and its usage..
IRepository repository { get; set; } //implement Interface and inject via IoC Container
//..usage
var employee = repository.GetEmployee(123); //get by id
//..new WorkSchedule
employee.WorkSchedules.Add(workSchedule);
var result = repository.Save(employee);
Since everything here is EF related, it isn't much of DDD. IF the code works as desired, then it's ok. But DDD has no relationship to EF or any other ORM. You should design the Domain objects, without caring at all about the database or an ORM. Then, in the repository you map the Domain entities to Persistence entities which will be handled by the ORM.
Also, my thinking right now Workschedule is a value object but I'm putting and ID for normalization purposes
This is the consequence when the layers and models are mixed. You don't need an ID in the domain but you need an id for persistence. Trying to fit both requirements in one model and calling that model Domain leads to nowhere.
EF it is not for DDD, it is too clumsy. EF is for same codemonkeys who likes t map SQL tables to Entities and do it like ActiveRecord antipatter, but after more intelligent developers started to call this as a bad practice, they started to use ORM, entities and continue monkeycoding.
I'm struggling with EF last 3 years to let it work DDD way. It successfully resists and wins. Without hacks it doesn't work.
The on-to-many relations still doesn't work as expected, there is not way to create entities with constructor, not the public properties and so on.
I'm working on my first real MVC application and I'm trying to follow general OOP best practices. I'm refactoring some simple business logic that I had in a controller into my domain model. I've been doing some reading lately and it seems pretty clear that I should put the logic somewhere in a domain model entity class in order to avoid the "anemic domain model" anti-pattern.
The application will allow people to purchase leases for parking spaces. Rates are determined by the length of the spot and whether or not the customer is a member of the business park.
So I have entity classes in my domain model that look like this (simplified):
public class Customer
{
int ID { get; set; }
string Name { get; set; }
bool IsMember { get; set; }
}
public class ParkingSpace
{
int ID { get; set; }
int Length { get; set; }
}
public class ParkingSpaceLease
{
int ID { get; set; }
DateTime OpenDate { get; set; }
DateTime CloseDate { get; set; }
Customer Customer { get; set; }
ParkingSpace ParkingSpace { get; set; }
}
Edit: Just to clarify the LeaseQuote is not an entity class as it is just used to display the cost breakdown to perspective customers and is not persisted anywhere.
public class LeaseQuote
{
int SubTotal { get; set; }
int Discount { get; set; }
int Total { get; set; }
}
Now as a feature of the application I need to be able to generate quotes for different customer and parking space combinations. The quotes will normally be accessed outside the context of actually creating a lease such as when a customer calls up to inquire about a price.
So what is the best way to go about this? Does it make sense to instantiate a new ParkingSpaceLease object inside the controller just to call a GetQuote method on it?
var lease = new ParkingSpaceLease();
var quote = lease.GetQuote(length: 168, isMember: true);
return Json(quote);
Or should the LeaseQuote class have the method?
var leaseQuote = new LeaseQuote();
var quote = leaseQuote.GetQuote(length: 168, isMember: true);
return Json(quote);
It feels strange putting the logic in the actual ParkingSpaceLease class. I guess it feels kind of "heavy" to create a new lease object when I know that I'm not going to actually do anything with it other than access the GetQuote method which seems kind of like a separate service.
So where should the GetQuote method go and why should it go there?
It almost sounds like your LeaseQuote isn't an entity and more of a business level class. I mean, you're not storing it in the database anywhere, are you? And it's not a part of another data object.
When I see this
Now as a feature of the application I need to be able to generate quotes for different customer and parking space combinations. The quotes will normally be accessed outside the context of actually creating a lease such as when a customer calls up to inquire about a price.
I think of a method signature like this
public LeaseQuote GetQuote(Customer customer, ParkingSpace parkingSpace, int length)
But with that in mind, I'd probably also want to store information about the cost of the parking space within the ParkingSpace entity and (if applicable) the customer's discount in the Customer entity.
Where would this stuff go? In a model class (business model, not LINQ or Entity model) that accesses your entities and serves as a provider for your controller.
Now I know that's not using your models exactly as written. And it could just be personal bias. But when I think about data models and data entities, they should not have any addon methods outside of what's coming back from the database. They should just represent the data unaltered as it appears in the database. If you're acting on the data, that belongs in a tier above the data entities.
Update:
What I am curious about from your example is why one would want to pass the full Entity objects (Customer and Parking Space) versus just the properties needed to perform the calculation?
It depends on your standard of code. Exposing the entity itself could be dangerous if the consuming code manipulates the entity. I prefer passing the entity mainly because that's what I'm used to. But I'm also careful not to manipulate the entity on the way in. That, and I think the method signature reflects what the GetQuote method is focused on; it's related to a customer and a parking space.
I could also make the case that if more fields go into the Entity later that can effect the GetQuote method, then the method signature doesn't have to change. In this case, only the implementation for GetQuote has to change.
Short answer: Preference.
Just make GetQuote a static method in ParkingSpaceLease.
I think you may have your object model slightly askew, which would lead to your concern about the lease being the wrong place from which to get a quote. It seems to me that a lease would be wholly composed by the parking space which is being leased, and would be related only to the customer purchasing the lease. IOW:
public class ParkingSpace
{
int ID { get; set; }
int Length { get; set; }
IEnumerable<ParkingSpaceLease> Leases { get; set; }
LeaseQuote GetQuote(Customer customer/*, other relevant parameters */) { ... }
}
public class ParkingSpaceLease
{
int ID { get; set; }
DateTime OpenDate { get; set; }
DateTime CloseDate { get; set; }
Customer Customer { get; set; }
}
public class LeaseQuote
{
//Properties
ParkingSpaceLease GetLease();
}
EDIT I missed the part about the LeaseQuote being a separate class.