Efficiently keep records of each change to some Core Data relationships
I'm designing a Core Data app which needs to keep dated records.
Imagine a user works with the program for a while and some records are stored. The user then changes important attributes and relationships (which transcend individual records), and continues using the program with this new configuration. Imagine now that the user looks back to the first records. I'd like to somehow store the old configuration so that, when the user is looking at any given record, the changed data (which, I 开发者_开发技巧repeat, transcends individual records) looks as it did when the record was written. (Note that the types of changes that need to be recorded are very infrequent.)
Storing a copy of the entire object graph, filed by date, each time a change is made, is obviously terrible (though it would provide the behavior I seek, if my description above was incomprehensible).
I considered storing only the changed objects each time, and deriving the up-to-date graph for any given record by collating all previous time periods. (If this were the case, how would I keep track of the lack of an object in a to-many relationship, I wondered? And would I be able to write something for NSManagedObject in general, or would I need to add this feature to each relevant entity?)
Is there a simpler or better way to do this sort of date-relative data storage?
Since you need to store the old relationships as well as individual objects, you really don't have a choice but to save a snapshot of the old object graph in some fashion.
There are several options for doing so:
(1) If the changes are rare and the graph small, then saving a snapshot of the entire object graph might be the simplest and most robust solution. Why add complexity for a seldom used feature?
(2) Use fetched relationships for all relationships. The fetch predicate will fetch on date stamp. The disadvantage of this is complexity. You have to configure a fetch for every relationship and nothing works automatically. Neither can the context enforce graph integrity as easily.
(3) Linked stack: Each entity has a previous and a next relationship that points to the previous and next version of itself. When an attribute/relationship is changed, a new object and new objects for its relation targets are pushed on their respective link stacks. This would clone a big chunk of the graph every time you made a change. Finding a previous graph would be a matter of walking the previous relationship until the proper date was found.
(4) Entities for relationships: Say you have two entities A
and B
. Normally, you would just have a relationship such as A<-->>B
. However, you need to persist old relationships so you create an intermediate entity whose sole task is to model and track the changing relationship between A
and B
. So something like:
AlinkB {
dateStamp:Date;
a<-->>A.theBs;
b<<-->B.theA;
}
To find a previous relationship, you would search the relationships for the right date range. You'll need a custom subclass for each so you automatically manage the adding and transversing of the link entities.
精彩评论