I am a little confused on the following. Should i be using navigation properties to get where i want to get to, or should i asked the repository? for example: I have the following class
public class Vehicle
{
public IList<Equipment> Equipment { get; set; }
}
public class Equipment
{
//.. Properties..
}
AS far as DDD is concerned, what would be the recommended way of going about getting equipment associated with a partiacular vehicle?
Option1:
Ask repository for vehicle and grab equipment from navigation property
public class VehicleService {
public IEnumerable<Equipment> GetVehicleEquipment(int vehicleId)
{
var vehicle = _repository.Get(vehicleId);
return vehicle.Equipment;
}
}
Option2:
Make a specialized repository method to be able to ask for equipment for a specific vehicle
public class VehicleService {
public IEnumerable<Equipment> GetVehicleEquipment(int vehicleId)
{
return _repository.GetEquipment(vehicleId);
}
}
Choose option1 if Vehicle is an aggregate root and Equiment is a local entity or a value object since only aggregates have their repositories.
Option 1 and Option2 are both fine if Equiment is also an aggregate root and you don't mind your aggregate root referencing other aggregate roots. But Option2 seems to be redundant in this case.
Choose Option2 if you follow "do not reference other aggregate roots" since you reference equipement's id instead and the navigation is not doable.
public class Vehicle
{
public IList<Guid> EquipmentIds { get; set; }
}
Related
If we have a bounded context with lets say 2 aggregates where aggregate1 publishes event1 and aggregate2 wants to react to it, we have 1 ways of doing it:
in process raising event1 > aggregate2 reacting to it
publish event1 to message bus and have some separate process pick it up & invoke aggregate2 method(s)
regardless of being within the same bounded context, if we want to make sure we don't lose event1 (application crashes between aggregate1 is saved, and aggregate2 is saved in reaction to event1, e.g.) i have a hard time finding examples of when would option 1 be better than option 2 (beyond maybe validation)?
i must be missing something but at this point of my knowledge, it seems like a pure theoretical concept to me without some real world value in terms of reliability and ability to maintain correct state.
of course that publishing a message and having separate process listen/react to it might seem like an overkill but is there any practical use of domain events that are not persisted somewhere (even within local DB which gets polled in which case i'd call that a primitive message bus)?
what am i missing?
What is a real world application of domain events within a bounded
context and process?
Requirements:
User can create categories.
Category names must be unique.
User can rename categories.
(Category will have a number of other properties unrelated to naming).
DDD Concepts:
A Category aggregate should be responsible for its own internal invariants, but cannot know the details about other Category aggregates.
How are you going to ensure that the Category Name for the current Category is globally unique without the Category having access to all other categories?
Answer: Domain Events
DomainEvent
public CategoryRenamed : DomainEvent
{
public Category Category { get; }
internal CategoryRenamed(Category category)
{
this.Category = category;
}
}
DomainEventHandler
public CategoryRenamedHandler : IDomainEventHandler<CategoryRenamed>
{
public CategoryRenamedHandler(CategoryRenamed domainEvent)
{
string proposedName = domainEvent.Category.Name;
// query database to ensure that proposedName is not already in use
if (inUse)
throw new Exception($"Name {proposedName} already in use." ;
}
}
Entity
public abstract class Entity
{
List<DomainEvent> _domainEvents = new List<DomainEvent>();
protected AddDomainEvent(DomainEvent domainEvent)
{
_domainEvents.Add(domainEvent);
}
public List<DomainEvent> DomainEvents => _domainEvents;
}
Category
public class Category : Entity
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public Category(Guid id, string name)
{
Id = id;
SetName(name);
}
public Rename(string name)
{
SetName(name);
}
void SetName(string name)
{
// Local Invariants
if (string.IsNullOrWhitespace(name))
throw new Exception("Invalid name");
Name = name;
// Add a domain event for the infrastructure to process
AddDomainEvent(new CategoryRenamed(this));
}
}
Command
public class AddCategoryCommand
{
public Guid Id { get; set; }
public string Name { get; set; }
}
CommandHandler
public class CommandHandler : ICommandHandler<AddCategoryCommand>
{
readonly ICategoryRepository _categoryRepository;
public CommandHandler(ICategoryRepository categoryRepository)
{
_categoryRepository = categoryRepository;
}
public void HandleCommand(AndCategoryCommand command)
{
Category newCategory = new(command.Id, command.Name);
// Check for domain events before committing to repository
DomainEventDispatcher.DispatchEvents(newCategory.DomainEvents);
// Dispatcher will find the CategoryRenamed event and send 'in-process'
// to CategoryRenamedHandler
// If name was is in use an error will be thrown by the handler (see above)
_categoryRepository.Add(newCategory);
}
}
Outcome
Your Category aggregate has enforced its own local invariants and the domain command and domainevent handling infrastructure has been leveraged to ensure uniqueness of name across all categories.
Imagine I have two "areas" in my API, inventory and orders. I can quite easily group all methods related to inventory into "/inventory/" and to orders "/orders/" routes.
However, when I go to the root page of API where all methods are shown (IndexOperations.html) all methods are mixed together into one big list.
Is there any way to group methods from different areas on that list? For example show something like this on the operations index page.
Inventory
Method1
Method2
Orders
Method1
Method2
Group your operations:
If you group your DTOs into a static class as shown below, then ordering will be taken care of automatically assuming you want the groups alphabetically.
public static class UserOperations
{
[Route("/Users","POST")]
public class CreateUserRequest
{
public string Name { get; set; }
public int Age { get; set; }
}
...
}
public static class DuckOperations
{
[Route("/Ducks","POST")]
public class CreateDuckRequest
{
public string Name { get; set; }
public int Age { get; set; }
}
...
}
Alternatively specify the sort:
The ServiceStack MetadataFeature in v4.09+ provides access to the IndexPageFilter which lets you specify specify the Sort function that is applied to the index pages' OperationNames, where the OperationName is the full type name of the DTO.
var metadata = Plugins.First(x => x is MetadataFeature) as MetadataFeature;
// This is the default sort, replace with one that groups
metadata.IndexPageFilter = (page) => page.OperationNames.Sort((a,b) => b.CompareTo(a));
I hope this helps.
BACKGROUND: I have a Person domain object. It is an aggregate root. I have included a portion of the class below.
I am exposing methods to perform the objects behaviors. For instance, to add a BankAccount I have the AddBankAccount() method. I have not included all the methods of the class but suffice to say that any public property must be updated using a method.
I am going to create an IPerson repository to handle the CRUD operations.
public interface IPersonRepository
{
void Save(Person p);
//...other methods
}
QUESTION: How do I tell the repository which fields need to be updated when we are updating an existing person? For example, If I add a bank account to an existing person how do I communicate this information to the repository when repository.Save() is called?
In the repository it is easy to determine when a new person is created, but when an existing person exists and you update fields on that person, i'm not sure how to communicate this to the repository.
I don't want to pollute my Person object with information about which fields are updated.
I could have separate methods on the repository like .UpdateEmail(), AddBankAccount() but that feels like overkill. I would like a simple .Save() method on the repository and it determines what needs to update in some manner.
How have others handled this situation?
I have searched the web and stackoverflow but haven't found anything. I must not be searching correctly because this seems like something simple when it comes to persistence within the DDD paradigm. I could also be way off on my understanding of DDD :-)
public class Person : DomainObject
{
public Person(int Id, string FirstName, string LastName,
string Name, string Email)
{
this.Id = Id;
this.CreditCards = new List<CreditCard>();
this.BankAccounts = new List<BankAccount>();
this.PhoneNumbers = new List<PhoneNumber>();
this.Sponsorships = new List<Sponsorship>();
}
public string FirstName { get; private set; }
public string LastName { get; private set; }
public string Name{ get; private set; }
public string Email { get; private set; }
public string LoginName { get; private set; }
public ICollection<CreditCard> CreditCards { get; private set; }
public ICollection<BankAccount> BankAccounts { get; private set; }
public ICollection<PhoneNumber> PhoneNumbers { get; private set; }
public void AddBankAccount(BankAccount accountToAdd, IBankAccountValidator bankAccountValidator)
{
bankAccountValidator.Validate(accountToAdd);
this.BankAccounts.Add(accountToAdd);
}
public void AddCreditCard(CreditCard creditCardToAdd, ICreditCardValidator ccValidator)
{
ccValidator.Validate(creditCardToAdd);
this.CreditCards.Add(creditCardToAdd);
}
public void UpdateEmail(string NewEmail)
{
this.Email = NewEmail;
}
There is an example of Repository interface from S#arp Architecture project. It is similar to PoEAA Data Mapper because it used to CRUD operations also.
public interface IRepositoryWithTypedId<T, IdT>
{
T Get(IdT id);
IList<T> GetAll();
IList<T> FindAll(IDictionary<string, object> propertyValuePairs);
T FindOne(IDictionary<string, object> propertyValuePairs);
T SaveOrUpdate(T entity);
void Delete(T entity);
IDbContext DbContext { get; }
}
As you can see, there is no update method for specific properties of an entity. The whole entity is provided as an argument into the method SaveOrUpdate.
When properties of your domain entity are being updated you should tell your Unit of Work that entity is 'dirty' and should be saved into storage (e.g. database)
You should not pollute your Person object with information about updated fields but it is needed to track information if entity is updated.
There might be methods of the class DomainObject which tell 'Unit of Work' if entity is 'new', 'dirty' or 'deleted'. And then your UoW itself might invoke proper repository methods - 'SaveOrUpdate' or 'Delete'.
Despite the fact that modern ORM Frameworks like NHibernate or EntityFramework have their own implementations of 'Unit of Work', people tend to write their own wrappers/ abstractions for them.
What I'm doing to solve this problem, is adding an interface to my domain objects:
interface IDirtyTracker {
bool IsDirty {get;}
void MarkClean();
void MarkDirty();
}
The base DomainObject class could implement IDirtyTracker, and then repositories etc. could use IsDirty to check if it's dirty or clean.
In each setter that makes a change:
void SetValue() {
this._value = newValue;
this.MarkDirty();
}
This does not give you fine grain checking, but it's a simple way to avoid some unnecessary updates at the repository level.
To make this a little easier, a GetPropertiesToIncludeInDirtyCheck method could be added, which would retrieve a list of properties which need to be checked.
interface IDirtyTracker {
IENumerable<Object> GetPropertiesToIncludeInDirtyCheck();
}
I have a question in regarding aggregate roots, should they have the responsibility for deleting child objects or should that be up to the repository? What if I wanna query one file by its Id, should I then create a specific method for this in my repository?
Code snippet of my aggregate root:
public class Folder {
#region Properties
public Guid Id { get;set; }
public Name { get;set; }
public virtual ICollection<File> Files { get;set; }
#endregion
#region Methods
public File AddFile(string type, string title, bool share = false)
{
///
}
#endregion
}
File class:
public class File
{
#region Properties
public virtual Folder Folder { get; set; }
public string Title { get; set; }
public string Type { get; set; }
public bool Shared { get; set; }
#endregion
#region Constructor
public File(Folder folder, string type, string title, bool share = false)
{
///
}
#endregion
}
Thanks
Aggregate root are responsible for domain invariants (see http://dddcommunity.org/library/vernon_2011/).
So the answer is yes, the aggregate root should be the only object that has access to the objects that it aggregates. This means that no other object should obtain a reference to a File and that File should not expose any method that change its own state.
All method that change the state of the child object should be exposed by the aggregate root itself, since it must ensure the aggregated invariants.
As to persisting the deletion, I usually model domain events as .NET events: such events are then subscribed by the Repository before returning the entity. Thus, in the event handler the persistence logic occurs (see http://epic.tesio.it/doc/manual/observable_entities.html for details)
This depends heavily on your context. If a file has its own lifecycle independent of the folder then you could make a File an entity/AR. This would, however, mean you need to break the instance aggregation relationship in the Folder so that it only has the reference to the File. Something like this:
public class Folder
{
public Guid Id { get;set; }
public string Name { get;set; }
public List<ContainedFile> Files { get;set; }
}
public class File
{
public Guid Id { get;set; }
public string Title { get;set; }
}
public class ContainedFile // or FolderFIle or whatever makes sense in your domain
{
public Guid FileId { get;set; }
}
Try to keep references to other AR instances out of an AR. Also, that bi-directional relationship (File.Folder) is not necessary. That is probably an indication that you are using your domain model for navigation :) --- try not to do that.
AggregateRoots should be responsible for their child objects. In the case of your example, imagine that the Folder exposes a Size property, which is determined from the sum of the size of Files.
long Size{get{return Files.Sum(f => f.Size);}
So when you're actually deleting the file, the folder would need to know about it.
You might not have the Size property now - but part of the purpose of following DDD is so that when you need to implement it it's easy and clean to do.
I have an aggregate named Campaigns every with a root entity named campaign, this root entity has a list of attempts (entity)
public class Attempts: IEntity<Attempts>
{
private int id;
public AttempNumber AttemptNumber {get;}
//other fields
}
public class Campaign: IEntity<Campaign> //root
{
private int id;
public IList<Attempt> {get;}
//other fields
}
Im using a method to add a campaign attempt
public virtual void AssignAttempts(Attempts att)
{
Validate.NotNull(att, "attemps are required for assignment");
this.attempts.add(att);
}
Problem comes when i try to edit a specific item in attempts list. I get Attempt by AttempNumber and pass it to editAttempt method but i dont know how to set the attempt without deleting whole list and recreate it again
public virtual void EditAttempts(Attempts att)
{
Validate.NotNull(att, "attemps are required for assignment");
}
Any help will be appreciated!
Thanks,
Pedro de la Cruz
First, I think there may be a slight problem with your domain model. It seems to me like 'Campaign' should be an aggregate root entity having a collection of 'Attempt' value objects (or entities). There is no 'Campaigns' aggregate unless you have a parent concept to a campaign which would contain a collection of campaigns. Also, there is no 'Attempts' entity. Instead a collection of 'Attempt' entities or values on the 'Campaign' entity. 'Attempt' may be an entity if it has identity outside of a 'Campaign', otherwise it is a value object. The code could be something like this:
class Campaign {
public string Id { get; set; }
public ICollection<Attempt> Attempts { get; private set; }
public Attempt GetAttempt(string id) {
return this.Attempts.FirstOrDefault(x => x.Number == id);
}
}
class Attempt {
public string Number { get; set; }
public string Attribute1 { get; set; }
}
If you retrieve an Attempt from the Campaign entity and then change some of the properties, you should not have to insert it back into the campaign entity, it is already there. This is how the code would look if you were using NHibernate (similar for other ORMs):
var campaign = this.Session.Get<Campaign>("some-id");
var attempt = campaign.GetAttempt("some-attempt-id");
attempt.Attribute1 = "some new value";
this.Session.Flush(); // will commit changes made to Attempt
You don't need an Edit method. Your code can modify the Attempts in-place, like so:
Attempt toModify = MyRepository.GetAttemptById(id);
toModify.Counter++;
toModify.Location = "Paris";
MyRepository.SaveChanges(); // to actually persist to the DB
Of course how you name the SaveChanges() is up to you, this is the way Entity Framework names its general Save method.