How to automatically delete any entity when all its relationships are nil? - ios

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.

Related

When you mark an entity as deleted it marks its children as well, is there a way to only mark the parent deleted?

When you mark an entity as deleted by setting the entityAspect it marks its children as deleted as well. Is there a way to only mark the parent deleted? Or a way to go through and mark the children as unchanged after the fact?
You don't want to mess with the navigation properties - I will tell you that straight away. My suggestion is to model your question as if you had to ask it using T-SQL.
In T-SQL, can you delete a parent record, but leave the children? No. I mean you could, but why? You just created orphaned child records in the database. Are you going to delete the foreign key but leave the data? What a mess.
The only reason you are able to map a parent child relationship in Breeze is because of the navigation properties that were created based on the parent / child relationships defined in the database. If you can't do it in the database, you can't do it in Breeze.
If the model refuses to budge and you decide to go forward with this anyway, you need to return data that is not linked via relationships. You can create a view for the parent and children... but you will need to manually manage the load. If your entities are based on a view, they probably are not going to be updatable.
Sorry, no code to post. I gave up on this a long time ago.
Breeze does not mark child entities as deleted if you delete the parent. We haven't implemented cascading deletes in Breeze. You must have code in your application that is doing this. Breeze disconnects the child entities from the deleted parent by clearing the foreign key properties, so the child entities will be in modified state. However, you won't be able to successfully save w/o violating FK constraints in your DB. You either have to implement cascading deletes on the server or manually delete the child entities.

Grails one to many relationship behavior

I know that one of the benefits of the one to many relationships is cascading behavior such as the deletion of a parent(owning) object resulting in
the deletion of the children(objects the parent owned) but what if the objects owned by it are also owned by another parent do they still get deleted if only one parent gets deleted?
GORM/Grails is smart enough to figure out in this case that the child instances should not be deleted when they are in use by another instance. (As indicated in my comments to the original question)

Coredata relationship breaks once the entity is updated

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.

Reassigning one-to-one relationship nulls previous object / CoreData iOS

I have 2 entities. ObjectA stores all ObjectB's objects through a many-to-many relationship. ObjectA also stores one specific object as a default object using a one-to-one relationship. The idea is to be able to assign many different child objects for EntityA while also keeping a specific reference to one specific child object. This idea works perfectly fine all throughout my project exempt in one circumstance(identical code and identical entity relationship setups.
The problem I am having is when I reassign the existing defaultObject to a new different object by simply ObjectA.defaultObject = someObject23; this assigns the new object correctly but in the process my original To-Many relationship reference to that existing defaultObject goes null.
The to-many relationship 'AllObjects' from EntityA has a Cascade delete rule for EntityB.
The One-To-One relationship 'DefaultObject' has a NULL delete rule for EntityB.
Both have inverses set.
Here is a real quick overview.
ObjectA.allObjects = 10 objects; // 1 of these is someObject1
ObjectA.defaultSomeObject = someObject1; // This works fine.
ObjectA.defaultSomeObject = someObject2; // This assigns the new defaultSomeObject=someObject2,
// but in the process it removes the someObject1 from my ObjectA.allObjects array (Goes NULL)
I'm stumped because like I say I have used this technique multiple times and the only workaround to this I have succeeded with is to "rig" it and actually save a reference to the previous object, delete it from the ObjectA array, set the new defaultObject, then write that object back to the array. There must be a simple explanation I am overlooking. More coffee? lol. Any help is greatly appreciated. I have tried all the different delete rules for each relationship as well just for kicks.
Problem solved. Definitely needed more coffee. What was happening was the one-to-one relationship was using the to-many relationship inverse causing it to do exactly what it was supposed to do, go null...

Replace entities in to-many relationship in Core Data

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]

Resources