I have an endpoint which is linking entity1 to entity2 (many to many), so after they were linked I need to send an integration event. I am using event sourcing and outbox pattern.
So what must be the aggregate of my event? entity1 or entity2
What must be the topic of my integration event? entity1 or entity2
Also in the event store(where I store domain events) I need to specify streamName, but as I understand it needs to be buisness valued entity name, so it cannot be like entity1_entity2 (the name of linking table)?
Related
I am currently trying to write an application in DDD allowing an entity to be created, updated and deleted. A change to an entity must be approved by another person. The application must also keep track of what changes were made to an entity. The simplified domain model looks like this:
The application has one bounded context containing ChangeSet, Enity and EntityHistory where ChangeSet is the aggregate root. I designed the aggregate this way because of an Entity should not be changed without a ChangeSet and furthermore a ChangeSet should be saved together with the edited entities in one transaction. On that account I designed a single aggregate.
The design work pretty good when creating new entities:
private void CreateChangeSet()
{
var repository = new ChangeSetRepository();
var entities = new List<Entity>
{
new Entity(Guid.NewGuid(), "Test1", new TagStatus(1, EntityState.Pending));
};
var changeSet = new ChangeSet("a user", "Added a new entity", DateTime.Now, ApprovalState.Submitted, entities);
repository.Insert(changeSet);
}
However, problems arise in my design occur when I am trying to edit an entity:
private void EditEnity()
{
var repository = new ChangeSetRepository();
var entity = repository.GetEntityByName("Test1");
entity.AssignName("a new name");
var entities = new List<Entity>{entity};
var cs = new ChangeSet("a user", "Added a new entity", DateTime.Now, ApprovalState.Submitted, entities);
repository.Insert(cs);
}
As far as I know an repository should return aggregates only, which would mean that in order to change an Entity I must first search for a ChangeSet which does not make sense. Is it a bad practice to return a sub-entity of an aggregate even if you perform changes only be the aggregate root?
I have searched the internet for an answer an many people are pointing out that this kind of query can point out a wrong design of aggregates. Which makes me think again if instead of one aggregate I need two aggregates one for the ChangeSet and one containing Entity and EntityHistory. Should I use two aggregates instead of one? If so how can I do this within a single transaction?
A further indication for two aggregates are user interface requirements like 'the user wants to see a change history for an entity' or 'show me all entities in a view'. On the one hand this indicates two aggregates on the other hand I have a feeling that ChangeSet and Entities should really belong together .
To sum up my questions:
Should I use one or two aggregates in my design?
If one aggregate: is it a bad practice to return a sub-entity of an aggregate even if you perform changes only through the aggregate root?
If two aggregates: how can I save the ChangeSet and the associated Entities in one transaction?
TL;DR:
You should use one entity.
Yes, it is bad practice as the behaviour should be exposed by the aggregate; also, reconstructing the Entity would require the Entity to know how to query ChangeSet; unless you orchestrate this at the service level, it is not great design.
You should not do it, as an aggregate root represents, IMHO, a transactional boundary.
Additional thoughts
If I understand correctly, you are trying to do what Event Sourcing does naturally, with the addition of the approval workflow. Events in an Event Store are approximately what you define with a ChangeSet.
If this is correct, you could model this elegantly in ES by:
Call an Edit Entity API that takes as input the bulk of the changes for an Entity
The API:
Builds a ChangeEntityCommand from the API input (command may fail validation);
Retrieves the Entity;
Invokes the corresponding Handler in the Entity aggregate, which in turn emits a ChangeQueuedForApprovalEvent.
Commits the Entity in the EventStore
An EventHandler will intercept the event above and take care of updating the approval view.
When the approver gives the green light, a similar flow will emit a ChangeApprovedEvent containing the same data of the former event. This event is the one that actually transforms the Entity.
Lastly, I do not believe that the ChangeSet modelling really suits DDD, as it fails to capture the intent of the change.
Hope this helps and good luck with your project.
I am working with an application that has several domain objects with their own mapping to a similar list of HasMany domain objects. The application is running on-top of a brownfield database, so the structure cannot be easily changed. Each parent fluent mapping looks similar to:
HasMany(x => x.Locations) // Location Type applicable to the given parent
.AsBag()
.KeyColumn("parent_sk")
.LazyLoad()
.Inverse()
.Cascade.AllDeleteOrphan();
Every time a location on a parent domain object is changed the associated parent objects must have their location properties synchronized (some new locations added, some deleted, others left as is) within the same transaction.
I've created and registered an NHibernate Event Listener that implements IPreUpdateEventListener, IPreInsertEventListener, and IPreDeleteEventListener. This event listener fires as expected when a change is made to any Location domain objects.
Once fired the proper parents are found and their Location collections are manipulated in order to add/remove locations. Parents are then sent to the appropriate repository save method. I'd expect the changes to the locations collection to cascade. This however is not the case.
When debugging I've verified that the expected values are present in the collection, but nothing is modified in the database, nor is anything attempted as far as I can tell via SHOW_SQL logs. If in the process I modify a non-relationship property on the parent the changes are indeed persisted on the parent, yet the children remain unchanged.
Is there a proper way to configure a listener to modify children of a HasMany in a cascade?
I would say, that the answer could be found in this Q&A:
NHibernate IPreUpdateEventListener, IPreInsertEventListener not saving to DB
that is in fact in the Ayende's article:
NHibernate IPreUpdateEventListener & IPreInsertEventListener
...Here comes the subtlety, however. We cannot just update the entity state. The reason for that is quite simple, the entity state was extracted from the entity and placed in the entity state, any change that we make to the entity state would not be reflected in the entity itself. That may cause the database row and the entity instance to go out of sync, and make cause a whole bunch of really nasty problems that you wouldn’t know where to begin debugging.
And the description how to solve that issue:
You have to update both the entity and the entity state in these two event listeners (this is not necessarily the case in other listeners, by the way)...
A small code snippet, which must be adjusted to the above needs (handling collection elements)
public bool OnPreUpdate(PreUpdateEvent #event)
{
...
Set(#event.Persister, #event.State, "UpdatedAt", time);
...
// the way how to assure that even the State is updated
private void Set(IEntityPersister persister, object[] state
, string propertyName, object value)
{
var index = Array.IndexOf(persister.PropertyNames, propertyName);
if (index == -1)
return;
state[index] = value;
}
So, keeping both entity and entity state updated, would be the solution here.
I expect the problem is the .Inverse() statement. That basically tells NHibernate that the location is responsible for the cascading and not the parent domain object... Removing the Inverse() would make the cascading work correctly.
I noticed something when i was reading through some Entity Framework's POCO classes that the one to many relationship is always represented in two ways like following :
1- Public List<User> Users {get;set;}
2- Public Virtual User Users {get;set}
So which one is right and when i should use each, this concept really confused me !!!
I think you've read that wrong. Typically (although not required), you would have navigation properties at both ends of the relationship.
A collection navigation property on the one side (a Department may have a List<User> for example) and a reference navigation property on the many side (a User would have one Department).
It is also recommended that you have a foreign key property as well, for example an int DepartmentId on the User.
You would need to mark the navigation properties as virtual if you wanted to support lazy loading. See here for the requirements on POCO types.
I have 5 entities that are loaded using the entity framework. Here they are:
All of the entities are inherited from:
(Each entity represented by a class with the properties described above. Al entities inherit Transmission entity).
As you can see, there are common properties in some of the entities. But the properties WorkerId, WorkerPersonalId, VehicleId, VehicleNumber, SubcontractorId has special methods for SET so in order to encapsulate the logic of update I created WorkerVehicleTransmission class with those properties setters implementation. Each transmission now uses the WorkerVehicleTransmission.
Now I have a new need. I need to log each property change. For that I have the Log() method. For eaxmple, I need that when the user makes cargoStorage.Weight=8; there will be a call to Log() that will log this change.
Importent issue: I need to find a solution where the creation of an entity (by the entity framework for example) will not log.
How can I integrate the new need?
This question is the real need for the example I ask about here: how to solve this code duplication + add another method
As a start you could attach a handler to the PropertyChanged event in the Transmission base class which will enable you to call the Log method whenever a property changes in any of your sub classes.
INotifyPropertyChanged.PropertyChanged Event
This however will fire when any change is made, including when the Entity Framework creates the objects, so is only half way there.
Edit
If you create a new property within the Transmission class (a boolean flag) you could use this in your data access object routines to set whether logging should be enabled.
This flag is only ever set after any Entity Framework activity on each object has been completed therefore the only Property changes logged are those relating to your code.
Not an elegant solution but I cannot see any other way.
Edit
Just had a look at the EntityObject base members and there is an Property (Enumeration) named EntityState.
EntityObject.EntityState Property
This property is set to "Detached" when the entity is being created (Unattached to the object context) by the Entity Framework and changes its value to "Added", "Deleted", "Modified" or "Unchanged" after it is added (depending on the state of the object).
By checking if the value is anything other than "Detached" you could then determine whether logging should be enabled.
With Linq To Sql - what is the best way to update the value of one table in a database when a value changes in a different table?
For example in TableA, there is a column called DateModified. TableA has an association to TableB. Now I want to set the value of the DateModified field to the current date every time the record changes in tableA AND everytime a child record is created/updated/deleted in TableB.
How can this be achieved?
If the change was just in the one record, you can use either the On*Changed partial methods, or you can override SubmitChanges on the data-context, call GetChangeSet, and apply the changes just before they are updated. The latter (data-context) approach is useful for catching a broad spectrum of changes, where-as the On*Changed approach is useful for logic specific to individual properties.
However, in the case presented (non-homogeneous updates), I expect a database trigger may be more appropriate.
You could register a PropertyChanged event handler on the child entity in OnCreated (implemented in a partial class) and have that handler update the parent property. If you don't care about the already loaded classes getting the change, using a DB trigger as #Marc suggests would also be an option.
EDIT: If you need to catch deletes as well, you can implement the delete partial method for the data context to call the same handler method to update the parent of the entity being deleted.
Either do Insert/Update/Deletes on TableB via a StoredProcedure which allows you to perform the update on TableA or have Insert/Update/Delete triggers on TableB which updates TableA
I wouldn't try to accomplish this in LINQ as it will involve either overriding various IDE-generated code structures (maintenance nightmare) or extra calls to the Database to get the related TableA item.