How can I access deleted entity in self tracking entities graph?
I understand that in case I use MarkAsDeleted on the objects contained in a collection they are moved to ObjectsRemovedFromCollectionProperties of the parent entity, but how to access deleted objects that are not in a collection?
Thanks
Jakub
Deleted reference is not directly exposed but you can debug ApplyChanges to see where it comes from. If you want to have the reference to deleted object you can simpy use return value from MarkAsDeleted.
Related
I have a simple Core Data app that has a many to many relationship from entity A to B. I have kept the delete rule as nullify.
I simply want that when all entities of type A that relate to an entity of type B are deleted. In other words, when all relationships from a given B to A are nil, that particularly object of entity B should be deleted.
Now I noticed that, at least for me, this isn't happening automatically. Do I have to manually check to see if a given B object has all relationship to A as nil and then delete them manually or is there an automatic way to achieve it?
In your NSManagedObject subclass
- (void)willSave
{
// Check for relationship and delete self if empty
}
...or is there an automatic way to have this happen?
Yes if you let Core Data to manage this.
If you have two entites, say Parent and Child where the former has a one-to-many relationships with the latter
you can set the children relationship with a Delete Rule Cascade.
On the contrary, the parent relationship would be
The check on the optional flag depends on if a Child could exist with or without a Parent associated with it.
Here the delete rules mean the following.
If I delete a parent, all the children will be deleted. If I delete a child, nothing would happen on the parent (in other words the parent won't be deleted).
The inverse relatioship between the Child and the Parent is very important since lets Core Data to maintain the graph consistency. So, you should (a must for me) use it in every model you have.
Is this what you want to achieve? Let me know if you need something else.
Update 1
Only children can be deleted and not the parent. And I want that when
all children of a given parent are deleted, the parent object should
be removed from the store as well. the parent cannot be directly
deleted.
Deleting a parent it's up to you. In your code you will just not delete a parent if you want. I would use the configuration I provided since, if you delete a child, the parent will remove the reference to it.
To delete all the children that belong to a specific parent I would use a simple fetch request against Child where the predicate would be
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"parent == %#", parentOfTheChildrenYouWantToDelete];
Once run, the request will return a NSArray of managed objects. for in to delete them.
In my understanding of your question, I recommend you look into running a specific fetch at a certain point in your code to check for nil against the relationship, and then delete manually.
So to answer your question, my understanding is that there is no "automatic" mechanism.
I am using coredata to save the server data through web services in my application and I am storing relationships as an object to the entity.
I have many entities e.g "Inspirations" and "Products" and both are related to each other. I have a problem whenever the records are updated in the third entity which is "Filters" then the relations of the entities broke and I cannot apply filters on the entities.
[object addRelatedInspirationsObject:related];
This is how I save relationships. I am not able to figure out why the relations are being broken once the entity is updated which has no direct link with the entity.
One thing more if I fetch and save the data of any one of the entities like "Inspirations" then all the relations start to work again.
Your code should work. Here are 2 things you need to check:
Make sure related is not nil when you call your method.
Make sure you call save on a valid managed object context.
From your question it seems that entities have 1 to many relationship between them. And by the code you supplied, every things should work fine. Just make sure, you are using the Filter object from the relationship like object.filter (or obj1.obj2.filter), not accessing it via a direct NSPredicate on Filter entity and updating it. And if you are using FRC, you might also need to generate a fault against the parent entities, to get your UI updates.
I found a question very similar to mine here, but it was un-replied to and unanswered so I will try again.
I may be missing something in regards to cascade deletes and core data. I am used to cascade deletes working as designed in RDBMS apps but having issues with core data.
I have an object record that get's inserted into entity via an "add form" called modally from a table view. No problem.
In another session I will insert objects into a related details entity (many) where there is a common loadID attribute in both. No problem.
In another session, I will call up the original table view to view the parent "loads", and swipe-delete, save the context, and the parent load gets deleted from the one side entity. No problem, (except apparently details objects in a many side entity do not get removed)
When I open the sqlite data source with a db manager, I see the child records (pay detail items) are being orphaned. I have double and triple checked the cascade delete settings in the relationships. Have tried different entity relationship settings combinations, but nothing seems to get the many records to automatically delete along with the parent record.
If you can't define corresponding keys in core data, how does core data know what belongs to what when you operate in multiple sessions (contexts) adding child objects to the many-side entity?
I don't know if I'm doing something wrong or missing a vital step prior to inserting new child objects in the many table, or doing something wrong or missing a step when deleting the parent object.
But I would suggest all with cascade deletes set to open your data file and be sure there are not orphaned objects (records)
I am trying to add an entity to the DB. Once I have added it, I want to detach it, so I can manipulate the object safely without making any changes to the DB. After calling context.SaveChanges() I do the following to detach the entity:
// save
context.Stories.Add(story);
// attach tags. They already exists in the database
foreach(var tag in story.Tags)
context.Entry(tag).State = System.Data.EntityState.Unchanged;
context.SaveChanges();
context.Entry(story).State = System.Data.EntityState.Detached;
However, changing the entity state to DETACHED will remove all related entities associated with the my entity. Is there a way to stop this ?
If I don't detach the entity, all my changes are sent to the DB next time I call context.SaveChanges()
Thanks!!
There is no way. It is limitation of EF. Your options are:
Not using the same context for another save (single context instance = single save)
Retrieve the entity from database again using another context instance which will not be used for saving
Create deep clone of your entity and use the clonned one (deep clone is done by serialization and immediate deserialization = your entity graph must be serializable)
I think there are two ways to approach this problem:
Purist: retrieving entities from a DbContext and modifying them without saving is a misuse of the tools and the architecture. Use a DTO instead.
Pragmatic: you can use AsNoTracking() to retrieve an entity graph that will not be tracked by the context for changes.
When I retrieve an entity from the one side of a one-to many relationship, I create a mutable array from the set that is the collection of entities from the relationship. I manipulate, edit or otherwise change those entities, possibly delete existing or add new.
When through with the changes I simply use the array to create a new set then replace the original set with that which I created like so:
self.myOneSideEntity.theManySideEntitiesRelationship = [NSSet setWithArray:myNewArrayOfEntities];
It occurred to me that replacing the set may not be deleting the old members. What happened to them? Is this the proper way to edit the collection of related objects? Am I leaving any kind of orphans or going against best practices with this technique?
My relationship is set up with an inverse, cascade delete on the one side, nullify on the many side and the inverse relationship is not optional.
I've spent some days to understand similar behavior in my application.
Relation's "Delete Rule" works only when the object that contains relation is deleted itself. If you simply replace one set of objects with another (as you do) - nothing happens. Child objects that were in old set will simply have inverse relations set to nil. So if that relation (from child side) is not optional, you will get CoreData error when saving context.
For now I didn't find any way to manage this, except manual deletion of old objects.
For me the issue was with getting objects which were wired with current object. (groupObject.docs)
It was solved when I add context by which I get this data.
I'm using MagicalRecord:
[GroupObject MR_findAllInContext:[NSManagedObjectContext MR_defaultContext]]
instead of
[GroupObject MR_findAll]