I've found nothing about migration rules in case of changing the deletion rule of a managedObjects relationship
My initial coredata model contained an entity with a relationship. The delete rule of this relationship was cascade. I had to change this behavior to Nullify.
Therefore I've created a new version of my coredata model but without any lightweight migration and it still works. So I wounder if I should have done adding a new version of my model or if the changing the deletion rules (e.g. from cascade to nullify) doesn't effect/need any migration.
Any suggestions?
Deletion rules specify the behavior of Core Data at runtime: If one object is deleted, other relationships may be set to NULL, or related objects may be deleted as well.
Therefore I assumed that the deletion rules are stored only in the Core Data model, but not in the persistent store file.
To verify this, I have created 2 store files from 2 Core Data models with identical entities, but different deletion rules. The NSStoreModelVersionHashes in the persistent stores metadata dictionary were identical.
In fact, both SQLite files were identical with the only exception of the "Z_UUID" in the "Z_METADATA" table, which is the NSStoreUUID of the persistent store file.
Also, addPersistentStoreWithType:... would fail if the version hashes of the loaded store are different from the hashes in the model.
Changing the deletion rules should therefore not be a problem.
Related
I found from this post I can remove all instances of an entity by fetching them all and deleting them all.
Isn't there any more efficient way to do removal? My consideration is I will have thousand of records within that entity.
There's no more efficient way, because CoreData is an ORM layer, not a database. Therefore you deal with objects and if you want them gone, you have to delete them.
A trick you may want to investigate is creating a parent object that would have a one-to-many relationship with the objects to delete. You could basically have only one of those that points to every entry in your big table. Set the cascade delete option on the relationship in your model. Then when comes time to purge, you just delete the parent object. Because of lazy loading, it won't try to load your other objects.
This being said, I haven't tried it myself, but it seems like a viable option.
In a special case where all instances of this entity are self-contained, it would be quicker to delete the backing file and re-initialize the management objects. This only works if your data can be arranged so that the temporary stuff is within its own store.
Otherwise, you'd probably get better results by using direct database access instead of core data.
I have a Core Data relationship between two entities, which is like this:
Entity A Entity B
aRelationship <-------------->> bRelationship
With the delete rule set to cascade.
Maybe I have this wrong, but I thought that if the delete rule for both of these relationships was set to "Cascade", then when did the following...
[context deleteObject:EntityA];
...it would also delete all the of the Entity B's associated with it. However when I log all of my entity B's it would seem that I am mistaken.
Could someone please shed some light on my confusion?
Thank you very much.
While it's not immediately apparent in the graphical data model editor each recipocal relationship i.e. each
<-->
...is really two separate relationship each with its own delete rule. Delete rules are activate when an object of the entity with the delete rule is deleted.
So, if in the data model editor you have two entities Alpha and Beta with a relationship:
Alpha.betas<-->>Beta.alpha
… then you really have two relationships like so:
Alpha.betas--(delete rule)-->>Beta.alpha
Beta.alpha--(delete rule)-->Alpha.betas
You never want to set up a delete rule like this:
Alpha.betas--(cascade)-->>Beta.alpha
Beta.alpha--(cascade)-->Alpha.betas
… because deleting any one Beta instance will delete the associate Alpha object which will trigger the deletion of all related Beta objects. Depending on the details of your data model, a reciprocal cascade can delete a big chunk of you data by accident.
What you really want is:
Alpha.betas--(cascade)-->>Beta.alpha
Beta.alpha--(nullify)-->Alpha.betas
Now, when you delete the Alpha object, it will delete all associated Beta objects.
When a cascade is blocked, it is usually a problem with a required relationship. Can't tell for certain without details of the data model.
It depends on what delete rules are you using.
Here is what Apple said in their document:
"When you delete a managed object it is important to consider its
relationships and in particular the delete rules specified for the
relationships. If all of a managed object's relationship delete rules
are Nullify, then for that object at least there is no additional work
to do (you may have to consider other objects that were at the
destination of the relationship—if the inverse relationship was either
mandatory or had a lower limit on cardinality, then the destination
object or objects might be in an invalid state). If a relationship
delete rule is Cascade, then deleting one object may result in the
deletion of others. If a rule is Deny, then before you delete an
object you must remove the destination object or objects from the
relationship, otherwise you will get a validation error when you save.
If a delete rule is No Action, then you must ensure that you take
whatever steps are necessary to ensure the integrity of the object
graph."
The link of “Relationship Delete Rules.”: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdRelationships.html#//apple_ref/doc/uid/TP40001857-SW1
I'd like to know what is the best practice to track and/or persist changes over time if I use EF. I'd like to get started with EF for a new project. What I need is a kind of change history.
That's how I did it before: If a record was created it was saved with an ID and with the same ID as InvariantID. If the record was updated i marked it as deleted and created a new record with the new values and a new ID but the same InvariantID. Like this I always had my current record but a history of changes as well.
This works perfectly fine for my scenarios. The amount of historical records is not an issue because I use this usually only for data that's not changing very often.
Is this build in EF somehow or what's the best way to get this behavior for EF?
No it is not build into EF and it will not work this way. I even don't think that it is a good approach on the database level because it makes referential integrity very complex.
With EF this will work only if you use following approach:
You will use conditional mapping for your entity - condition will be IsDeleted = 0. It will ensure that only non deleted entities will be used in queries.
You will have mapped stored procedure for delete operation to correctly set IsDeleted = 1 instead of really deleting the record
You will have to manually call DeleteObject to delete your record and after that you will insert new record - the reason is that EF is not able to deal with scenario where entity change its PK value during update.
Your entities will not be able to participate in relations unless you manually rebuild referential integrity with some other stored procedure
You will need stored procedure to query historical (deleted) records
I have an iPhone Core Data app with a pre-populated sqlite "baseline" database. Can I add a second smaller sqlite database with the same tables as my pre-populated "baseline" database but with additional / complementary data such that Core Data will happily union the data from both databases and, ultimately, present to me as if it was all a single data source?
Idea that I had is:
1) the "baseline" database never changes.
2) I can download the smaller "complementary" sqlite database for additional data as and when I need to (I'm assuming downloading sqlite database is allowed, please comment if otherwise).
3) Core Data is then able to union data from 1 & 2. I can then reference this unified data by calling my defined Core Data managed object model.
Hope this makes sense.
Thanks in advance.
Core Data is designed to handle multiple data files via the – addPersistentStoreWithType:configuration:URL:options:error: method. This will allow you to combine all of the data files together and then access them via a single NSManagedObjectContext.
Your only issue, and it may not even be an issue for you, is that the store files cannot directly reference each other. Therefore you will need to reference data between files "manually" via unique identifiers. However I suspect you are already aware of that limitation.
Manual Relationships
The idea is that when both objects in a "relationship" are in one model and one file, Core Data does its magic and handles all of the referential integrity for you. However when they are in different files and/or models this doesn't happen automatically anymore.
The solution to this issue is to use a fetched property that looks up some unique identifier to retrieve the entity (or entities) that you want to be on the other side of the relationship. This will give you a "weak" relationship between files.
One thing to note though when doing this. The fetched property does not get updated automatically when something changes. This means when data changes that would cause that relationship to change, your application will not be automatically made aware of it and you will need to request that property again to get the updated relationship information.
Hopefully that makes it a bit clearer.
Co-existance of fetched properties and relationships
They can definitely co-exist but realize that they are two separate properties. If you want your controller code to see them as one, then I would suggest building a subclass for that entity and then adding a convenience method in there that hits both the relationship and the fetched property and then rolls them up into one NSArray or NSSet before returning it back to your controller code.
You can attach the downloaded database with ATTACH DATABASE statement and operate with unions of tables.
Does anyone know how to delete an object and all of its related entities inside of EF without manually traversing the object graph and deleting each one?
For example, I've got SalesOrder and SalesOrderDetails with a 1:N relationship between them. When I delete a SalesOrder, I want all SalesOrderDetails to be deleted automatically.
Is this possible in EF?
You should not be doing this in the Entity Framework. All popular relational databases support ON CASCADE DELETE on foreign keys which is a lot more efficient as well. I suggest you just go with that.
in this article, Alex Jamese (who post his answer), has a complete article on the topic.
Link
The EF is responsible for the correctness of the ObjectContext after SaveChanges(). So the EF attempts to synchronize the ObjectContext, with the expected database state after the expected cascade in the database.
A tell tale sign of this is that if you open up something like SqlProfiler, you will notice the EF issuing DELETE requests for dependent entities that it knows about (i.e. that are loaded in the ObjectContext) when a principal is deleted.
Essentially what is happening here is that the Entity Framework expects that deleting the principal in the database, will delete all it’s dependents in the database. So it issues, what should be, a redundant DELETE to request itself so the dependents already loaded are deleted from the ObjectContext.
The key thing to note is that the EF does not retrieve all the dependent entities and issue deletes for them: It only deletes dependents that are already in memory.