I'm making a core data model, and I have a Client entity that has a to-many relationship to an Appointment entity. An Appointment can turn into a Transaction (if it has been paid for etc.), and I need to keep track of the Appointments of Clients that have turned into Transactions (where Transaction is an entity along with other attributes). A Client can have multiple Transactions, and a Transaction can have multiple Clients (optional). If I put a relationship between Transaction and Client, then I don't think there's a way I can detect which of the appointments have turned into transactions and which haven't...
Any help as to how I can set my model up to do this would be appreciated.
Thanks
I think there are more than one way of doing it. This is one I think works:
If Transaction is another entity, and Appointment has a one-to-one relationship to Transaction. Then you can leave the Transaction entity to be nil if unpaid. If paid, you set up Transaction and link up with its relationship to Appointment and Client. By checking if your Appointment's Transaction is nil, you know if it's turned into Transaction or not.
If you need detailed information about the transformation between the appointment and transaction you could make that transformation itself an entity and make it persistent. The new transform entity could have various properties like:
date (when did the transformation happened)
type (did the appointment transform into a transaction, was canceled or delayed)
etc
and relations:
from (the original appointment)
to (the resulting transaction/appointment/etc)
This way the relation between client and translation would look like this
Client->Appointent->Transform->Transaction
If the only difference between Appointent and Transaction is being paid or not, you can consider using only Transaction and a flag (paid/not paid).
Client->Transaction->Transform->Transaction
Related
Lets say an Invoice was generated for a Customer. This specific event would look something like this:
invoice.raised {
"id": "4dbcff82-6f35-4155-9aec-f8185c1f932f",
"total": "50.00",
"description": "Order 01133",
"customer_id": "c2206843-414d-454f-9894-57c6b11b9c00"
}
This is fairly simple example and it refers to customer aggregate that an invoice belongs to.
Difficulty manifests itself when I want to create Invoices view and I want to embed Customer's name in an invoice. I could do two things - enrich the original event to contain Customer's name or load up the Customers view to find out what the name is when I am building my Invoices view.
Now this is not a very complicated example, but in some cases it becomes almost unmanageable to enrich events anymore as I end up with a lot of properties of various aggregates copied into the event that is very specific to some other aggregate.
Is there a universally accepted way of dealing with this apart from enriching events? Because everytime now the invoice.cancelled event is raised I will have to also include the amount of the invoice once again, so that I can update Customers view with new balance for instance.
in some cases it becomes almost unmanageable to enrich events anymore as I end up with a lot of properties of various aggregates copied into the event that is very specific to some other aggregate.
That's right, it makes your events less manageable.
So I'd say that it's enough to have just customer_id and ask for customer name when you build your read model:
It can be at projecting time, when denormalised view is built.
It can be at querying time, when resulted view model is built based on invoices and customers (for this use case you can have dedicated list of customers with customer_id and customer_name only)
Because everytime now the invoice.cancelled event is raised I will have to also include the amount of the invoice once again, so that I can update Customers view with new balance for instance.
invoice.cancelled event is triggered by Invoice aggregate root, I expect, and it owns amount so it is natural to put amount into invoice.cancelled event.
invoice.raised event is triggered by Invoice aggregate root too but it does not own customer name. It cannot check if customer name is consistent at specific point in time anyway. That's why instead of embedding customer name you can simly query it when you build your read model.
BTW there is a good reading about designing events - 6 Code Smells with your CQRS Events – and How to Avoid Them
Difficulty manifests itself when I want to create Invoices view and I want to embed Customer's name in an invoice.
Is there a universally accepted way of dealing with this apart from enriching events?
You don't want to go down the road of enriching events if you can possibly help it -- that increases the coupling in your implementation, which makes changing your model more expensive.
UI Composition techniques might guide you in a useful direction. Udi Dahan wrote about them a number of times. Some examples
UI Composition Techniques...
Secret of Better UI Composition
The basic plot - instead of InvoiceView fetching Customer state, and using that state to produce a view of the customer, instead the InvoiceView delegates a share of the responsibility to the Customer component itself
InvoiceView (e : invoice.raised) {
InvoiceWidget(e.id)
CustomerWidget(e.customer_id)
}
I have several aggregates: Deposit, Withdraw etc. Now there is a VO called Ledger, which has other related VOs as well. Ledger marks the transaction for both the Deposit and Withdraw, which ever takes place. In this case, it seems similar to making a separate aggregate(creating a folder and placing Ledger and related types into it). But DDD won't allow me that, because Aggregate roots can only be Entities.
What can be the possible solution for it? How can I categorize and place Ledger and related VOs while staying in the boundaries of DDD?
UPDATE:
The ledger is like a record, a transaction for each operation performed. For example, when a deposit has been made, a trade has occurred etc. So it has no state, and will be just saved once and never modified again. It is persisted for record keeping purposes.
Deposit and Withdraw both have states and a lifetime, their status will change from Pending to Confirmation, or from Pending to Cancelled. So they cannot be services.
Please let me know if more information is required.
Thanks in advance.
From your update, it sounds as though you might have a slight terminology issue and a missing entity.
You might need to rename your Ledger value object to LedgerRecord or LedgerEntry.
Your missing entity might then be a Ledger (a ledger is like a book, a container of records or entries). This would have a collection of LedgerRecords.
So you would then maybe call Ledger.MakeEntry(text) or maybe call LedgerService.GetLedgerSectionByDateRange(from, to), which would return a Ledger populated with LedgerRecords from that date range, etc.
First, think of the rest of VOs that are part of the Ledger. Is there any hidden identity that you haven't considered before among these VOs? In that case, that would be the (root) Entity and you would have your Aggregate.
If that's not the case, you could consider whether the Ledger is a VO that is part of an Aggregate in which the root entity is Operation, where Operation is an Entity with unique identity and Withdraw and Deposit would be specializations of it.
I am trying to write a simple personal finance app for my own use and have the following issue and wondered if anybody can set me straight.
My data model is quite simple, I have 'account' managed objects which have an NSSet of 'transaction' managed objects which in turn have an NSSet of 'split' managed objects.
The 'split' object has a category and an amount so any transaction can be made up of multiple categories with differing amounts. e.g transaction total is £40 made up from £25 - Food and £15 - Fuel etc
The 'transaction' managed object can also have an optional 1 to 1 relation with another 'transaction' managed object. This is for when I want to represent a transfer. Therefore I have 2 'transaction' objects with the same attributes like date etc but each belongs to a different 'account' so shows up when I query for a list of transactions for an account.
I have overridden the appropriate setters on the 'transaction' managed object like setDate so that when this is called, it checks to see if it has another 'transaction' managed object linked to it and if it has, also changes the date of that transaction. That way changes made to one transaction are reflected in the other account transaction.
Still with me..? Now the problem is with the NSSet of 'split' objects for a transaction.
Lets say I created a new transaction in account A.
I set the date for the transaction
I create a 'split' object for the transaction which for arguments sake has a category of food for £20.
In my UI, I then say this transaction is a transfer. This prompts me to pick the account I want to transfer to, I pick account B.
In the background, a new 'transaction' object is created, its account is set to account B, I copy across the date etc from the original transaction in account a but I want to set both 'transaction' objects to point to the same NSSet of 'splits'.
That way, if I change the category or amount in the split of one of the transactions its reflected in the other? Changes to the simpler attributes are handled through the setters like setDate mentioned before. Can both 'transaction' objects point to the same NSSet of splits or do I manually have to synchronise the changes to both sets when a change is made?
Hope this makes sense and thanks for any help received.
Your relationship would need to be many:many between transaction and split entities.
If you want to do that then it would be better to create custom methods for setting both the transfer and splits rather than trying to override. You do need to write the logic for how one relationship is updated based on a change to another objects relationship. Once you have the relationship configured the objects at the other end are common so changes to the split instances are trivial.
It's also a good idea to be using mogenerator to manage your custom code separately to the auto generated code.
I would suggest changing your model.
The Transaction entity is for data shared by the Split entity like date and description. Each Transaction always has at least 1 Split (or 2 Splits if you are making the system double entry accounting). You can expose the transaction properties through the Split entity.
Your Account entity won't have a direct relationship to Transaction. It will only have a direct relationship to the Split entity.
I have a Transaction entity that has a unidirectional to-many relationship with a Product entity. I've made it unidirectional because I want a transaction to be associated with a product, but I don't want a product to be associated with any transactions.
I know Apple suggest that you should make relationships have inverses, but I don't think having an inverse relationship from Product to Transaction is appropriate here is it? I know I will have to manually set the deletion of the product from the Transaction if a Product is deleted, but that's fine.
Does it matter what the delete rule is for the unidirectional relationship, since it won't make any difference will it?
Thanks
You should make the inverse, even if you aren't going to directly use it. There is a reason that Apple suggests doing this:
Core Data uses this information to ensure the consistency of the
object graph if a change is made (see “Manipulating Relationships and
Object Graph Integrity”).
The question I have for you is, why wouldn't you set the inverse? If you don't want the product to be associated with Transactions, then just don't access that relationship.
I'm facing a typical DDD problem. It must be very basic. I have an order and customer.
A customer can create multiple orders. Customer is the root of its own aggregate. Order is the root of its own aggregate. But when a customer creates an order, we display some portion of the customer information on the order. Should Order aggregate hold reference to customer?
When it holds it then when the Order Repository gets the order, we are able to retrieve some portion of customer information as well for display. But when we involve the order in a transaction, customer also gets into it which is creating problem if the customer is also getting updated at the same time. Please advise guys ! My gut feeling says I MUST not hold reference to customer from order.
Question 2: (NEW)
Can I get and hold a reference to the Customer (from Customer Repository) for a given Order while creating an Order (using Order Factory) and safely save the Order (without updating the Customer inside in anyway, Customer is there only for information/query?) without creating contention if the same Customer is getting modified else where? Lets assume NHibernate as ORM.
A simple answer will be that you hold the ID of the customer or, if needed for your domain some ValueObject with a minimal set of information about the customer ( ID, Name ).
A more complex answer is to think about Bounded Context. See Eric Evans's presentation where he wishes he had put the BC chapter as the first chapter in the book.
The idea is that in your Customer Management Bounded Context, your Customer entity can be the AR of the Customer Aggregate and the Orders can be entities in the Customer Aggregate. In the Billing Bounded Context you can have an Order AR with a Customer entity inside.