NSFetchedResultsController notify for changes in another entity (Best practice) - core-data

I have two entities (MetaData and Prices) with a many-to-many relationship. The entity MetaData has an attribute dataIsInvalid to invalidate all related prices in the entity Price. I'm using a NSFetchedResultsController for MetaData and one FRC for Price.
The predicate for FRC Price is #"ANY metaData.dataIsInvalid == 0". Of course, if I change the dataIsInvalid attribute in MetaData, the controllerDidChangeContent method from FRC Price is not called, but the method in FRC MetaData. So I want to reload the FRC Price data in the controllerDidChangeContent method from FRC MetaData.
The problem is, that the FRC Price cannot see the changes in MetaData at that time. So that doesn't work.
What is the best practice for this scenario? Should I use NSNotificationCenterwith NSManagedObjectContextDidSaveNotification? This will be called after saveToPersistentStore and the FRC Price can see the changes.
Thanks for Help.

Related

Can an aggregate have lite version of another aggregate just for read?

I have an order aggregate with Order as root having multiple OrderLine. OrderLine has "identity reference" to Product aggregate. But having only "identity reference" is not enough. I need value of "taxable" property, last "price" property for calculating price in OrderLine. In fact, in order to calculate price in OrderLine, some data from Product aggregate is needed.
How can this problem is resolved in DDD? Is it valid in DDD approach to have a lite version of Product (ProductLite) to use as read-only DTO?
-- UPDATE (thanks to #Francesc Castells)
// app service to add OrderLine
product = productRepo.Read(productId)
orderItemPrice = priceDomainService.CalculatePrice(product.price, product.tax)
order.AddOrderLine(product.ID, orderItemPrice)
orderRepo.Save(order)
Yes, this is perfectly valid. An aggregate should store all data that it needs to fulfill its purpose. This data doesn't have to always be user input, it can also come from other aggregates. There's abviously a difference between data produced by an aggregate and data consumed by it. For example, your Order consumes product prices, but it cannot change the product price and expect the rest of the system to respect that new price, as it doesn't own it.
In your scenario, I would say that once in the OrderLine, the Price is not part of the Product anymore, but part of the OrderLine itself, which could probably be defined as the price of the product the moment it was ordered or maybe the moment it was put in the shopping cart.

NSFetchedResultsController update when relationship updates?

Imagine I have a data model that has 2 entities: Movie and Genre.
A Movie can belong to many Genres, as a Genre can have many Movies.
Now. I want to have a NSFetchedResultsController that observes the Genre entity (using the genre's name as a sectionNameKeyPath)
Say I import some data, and a Genre gets a Movie added to it during the import.
The question is: Will the NSFetchedResultsController delegate (controllerWillChangeContent: , etc.) methods be called (because the Genre.movies.count has changed)?
If not, how can I make that happen? In Swift?
(Yes I know there are other questions like this out there, but none seem to be succinct or have an official answer)
(May be related to this issue:)
Yes, it will update if the relationship on the entity updates. It will not update if a property in Movie changes even if the predicate is set to monitor that.
YES, on import of a Movie to a Genre, controllerWillChangeContent: of the FetchedResultsController observing Genre will be invoked.

Core Data Managed Objects Sets

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.

Core data relationship confusion

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

What's the Best Way to Simulate an Array Type Attribue in Core Data?

I've got a list of contacts, each having several emails.
Should I create a Contact Core Data entity and a Email entity and link several email objects to one contact object? Or should I do it another way e.g concatenate all the emails and store them as one big string?
What's the cleanest and most efficient way to deal with such a configuration ?
Thanks
Always think of Core Data as an object graph and model your data accordingly.
You should have a Contact entity and an Email entity. The email should be on the other end of a one-to-many bi-directional relationship with Contact. If you care about a specific order then you should also have some orderable value in the Email entity for later sorting.
Should I create a contact CoreData entity and a email entity and link several email objects to one contact object ?
This solution sounds reasonable. Still it is not an "array type attribute" as to-many relations are unordered sets instead of ordered arrays.
Your entity graph would look something like (pseudocode):
Contact{
name:string
emailAddress:string
//...other attributes of contacts
emails<--(optional,cascade)-->>Email.contact
}
Email{
from:string
// ... other attributes of emails
contact<<--(required,nullify)-->Contact.emails
}
In both the entity (abstract) and object (concrete) graphs, you need only link contacts to their emails without any particular order. You shouldn't worry about ordering the relationships in the entity graph because the order in which you want to display the objects might change from moment-to-moment. That order is determined by the sort descriptor of each particular fetch request. The fetch request will return an array in any order you define. E.g one time you want emails sorted by date received, another time by from, another time by some other attribute. You can even resort the array the returned by a fetch to get exactly the order you want.
You just want to make sure that the entities have attributes that capture the information on which you want to sort.
In the very rare cases in which some type of ordering is absolutely required in the entity graph itself, you should add a ordering attribute to the entity itself and write custom code to maintain the sort order.

Resources