I'm currently learning to use Core Data on iOS , in my test application I have two entities with an inverse relation, the delete cascade is working fine but i wonder if it is possible to have a update or insert cascade as well? for example if I create a new instance of entity 1 i want some of its attributes to be copied onto a new object of entity 2.
Do I have to write some code for this or is there some built in solution?
searching the internet gave me no results.
(also since I'm new to Core Data i'm thinking in terms of tables as my persistent store is of SQLite so an insert into one table must essentially copy a few attributes into another table)
Try to think of it in a different way. If those two objects share those properties, perhaps it would be best to create another entity who contains those fields and entity 1 and entity 2 would both have a common relationship to. Having multiple copies of the same data just doesn't seem like a good idea where it can be avoided.
(You haven't mentioned multiplicity of the relationship, which could be important.)
Not sure if this directly addresses your question, but …
If you have A <--> B. (1-to-1 relationship)
Cascade rules:
A cascades: B
B nils: A
(this is an A "owns" B description)
(above A/B == entities, below A/B == instances of entities)
if A(1) -> B(2)
and then you set
A(3) -> B(2)
B(2)'s reverse relationship to A(1) is nil'd out before it's set to A(3)
A(1) is left with a nil value (if that's not valid in the data model description, you're now in trouble, otherwise, it's B-less)
A(1) -> <nil>
Related
I have two tables of data. One is table_A(id, x, x, b_id) and table_B(id, x).
I would like to add a relationship between b_id from table_A to id of table_B. I already have a JSON data like that, and I tried with Xcode to make so connection, but all I can make is a new relationship between those two.
I'm new to this, so would apreciate any help.
You are thinking of CoreData in terms of a DBMS which it is not. You don't need to set up foreign keys to make relationships in CoreData. If you want to assign a B table entity to a A you just create a relationship of between the two and you can set the attribute. The foreignKey and linking is all done by CoreData in the background.
I'm new to Core Data and I'm trying to implement it into my existing project. Here is my model:
Now, there's some things that don't make sense to me, likely because I haven't modelled it correctly.
CMAJournal is my top level object with an ordered set of CMAEntry objects and an ordered set of CMAUserDefine objects.
Here's my problem:
Each CMAUserDefine object has an ordered set of objects. For example, the "Baits" CMAUserDefine will have an ordered set of CMABait objects, the "Species" CMAUserDefine will have an ordered set of CMASpecies objects, etc.
Each CMAEntry object has attributes like baitUsed, fishSpecies, etc. that point to an object in the respective CMAUserDefine object. This is so if changes are made, each CMAEntry that references that object is also changed.
Now, from what I've read I should have inverses for each of my relationships. This doesn't make sense in my model. For example, I could have 5 CMAEntry objects whose baitUsed property points to the same CMABait object. Which CMAEntry does the CMABait's entry property point to if there are 5 CMAEntry objects that reference that CMABait? I don't think it should point to anything.
What I want is for all CMAUserDefine objects (i.e. all CMABait, CMASpecies, CMALocation, etc. objects) to be stored in the CMAJournal userDefines set, and have those objects be referenced in each CMAEntry.
I originally had this working great with NSArchiving, but the archive file size was MASSIVE. I mean, 18+ MB for 16 or so entries (which included about 20 images). And from what I've read, Core Data is something I should learn anyway.
So I'm wondering, is my model wrong? Did I take the wrong approach? Is there a more efficient way of using NSArchiver that will better fit my needs?
I hope that makes sense. Please let me know if I need to explain it better.
Thanks!
E: What lead me to this question is getting a bunch of "Dangling reference to an invalid object." = "" errors when trying to save.
A. Some Basics
Core Data needs a inverse relationship to model the relationship. To make a long story short:
In an object graph as modeled by Core Data a reference semantically points from the source object to a destination object. Therefore you use a single reference as CMASpecies's fishSpecies to model a to-one relationship and a collection as NSSet to model a to-many relationship. You do not care about the type of the inverse relationship. In many cases you do not have one at all.
In a relational data base relationships are modeled differently: If you have a 1:N (one-to-many) relationship the relationship is stored on the destination side. The reason for this is, that in a rDB every entity has a fixed size and therefore cannot reference a variable number of destinations. If you have a many-to-many relationship (N:M), a additional table is needed.
As you can see, in an object graph the types of relationships are to-one and to-many only depending on the source, while in rDB the types of relationships are one-to-one, one-to-many, many-to-many depending on both source and destination.
To select the right kind of rDB modeling Core Data wants to know the type of the inverse relationship.
Type Object graph Inverse | rDB
1:1 to-one id to-one id | source or destination attribute
1:N collection to-one id | destination attribute
N:M collection collection | additional table with two attributes
B. To your Q
In your case, if a CMAEntry object refers exactly one CMASpecies object, but a CMASpecies object can be referred by many CMAEntry objects, this simply means that the inverse relationship is a to-many relationship.
Yes, it is strange for a OOP developer to have such inverse relationships. For a SQL developer, it is the usual case. Developing an ORM (object relational mapper) this is one of the problems. (I know that, because I'm doing that for Objective-Cloud right now. But I did if different, more the OOP's point of view.) Every solution is a kind of unusual for one side. Somebody called ORM the "vietnam of software development".
To have a more simple example: Modeling a sports league you will find yourself having a entity Match with the properties homeTeam and guestTeam. You want to have an inverse relationship, no not homeMatches and guestMatches, but simply matches. This is obviously no inverse. Simply add inverse relationship, if Core Data wants and don't care about it.
I have EntityA which has a navigation property to EntityB. In the frontend it's possible to create a new EntityA and append it to EntityB. If I now try to save the new created EntityA, Breeze also want's to save the changes on EntityB (containing the new ID of the newly created EntityA). Is it somehow possible to avoid having EntityB, because in this specific use case it should be possible to append new entities to EntityB, but these should not be saved back (and also not be reported as pending changes)?
I see the possibility with using two EntityManagers, but this would mean that I can no longer have navigation properties between the two types.
Pascal is asking an important question: are Entity A and Entity B related one-to-one? More to the point are they related one-to-one such that A depends on B (i.e. A is a child of B)?
A typical relationship of this sort is the "extension" entity. Consider "Order" and "OrderExtension". "OrderExtension" is a bolt-on type with optional fields that "extend" the core order data. An order can have zero or one "OrderExtension" records.
Order is the parent in this example; it SHOULD NOT have a FK reference to the OrderExtension. The OrderExtension is the child and it SHOULD HAVE a required OrderID FK field. The parent Order can exist without a child, but the child OrderExtension cannot exist w/o the parent.
At least that's how I think it should be. I've often seen folks turn this around. They give the Order an OrderExtensionID FK field which is optional. The OrderExtension has no backpointer to the Order.
The weakness of this design is that it allows you to create multiple orphaned OrderExtension entities that don't belong to anything ... and you'll rarely know they are there.
I'm betting that's your situation. I'm betting that Entity B is like OrderExtension and Entity A is like Order. When you created the OrderExtension (B) and associated it with an Order (A), Breeze tried to maintain that relationship for you by updating the Order.OrderExtensionID property. That puts Order (A) in a modified state.
DO not proceed until you've figured this out. While Jeremy is correct that you can save one entity by cherry picking the pending changes - you can save B without saving A -, you risk breaking the integrity of your data!
From a modeling perspective you've made Entity A dependent on Entity B. If you don't save A at the same time you save B, there will be no way for someone using the database to know that the two are related.
Next time you query for either of them, neither you nor Breeze will know they are related. You will be unable to navigate between A and B. I'm pretty sure that's not what you had in mind.
You can pass an array containing the entities you wish to save to the saveChanges method to restrict which entities are saved.
From the breeze docs:
saveChanges ( [entities] [saveOptions] [callback] [errorCallback] ) async
Saves either a list of specified entities or all changed entities
within this EntityManager. If there are no changes to any of the
entities specified then there will be no server side call made but a
valid 'empty' saveResult will still be returned.
Parameters:
[entities] Array of Entity optional The list of entities to save.
Every entity in that list will be sent to the server, whether changed
or unchanged, as long as it is attached to this EntityManager. If this
parameter is omitted, null or empty (the usual case), every entity
with pending changes in this EntityManager will be saved.
I'm struggling with creating a suitable Core Data model for my app. I'm hoping someone here can provide some guidance.
I have two entities -- "Goals" and "Items". The Goals entity contains only a goal description, but any goal may have any number of subgoals, and these may extend multiple levels in a tree structure. Subgoals are to be contained within the same entity, so presumably the Goal entity will contain a pointer to "parent" which will be the parent goal of any subgoal.
There will also be an "Items" entity that contains a couple of text fields and a couple of binary items, and must be linked (ideally, by a unique identifier, perhaps objectID) to the particular goal or subgoal the item(s) are related to.
I am totally fumbling with how to set this model up. I know what attributes need to be in each entity, but the relationships, particularly between goals and "subgoals", has me stumped. I don't seem to be able to turn up any good examples of tree structures in Core Data on the Internet, and even the couple of books I have on Core Data don't seem to address it.
Can anyone here help an old SQL programmer get headed the right direction with these relationships in Core Data? Thanks.
Have you tried creating a one-to-many from Goal to itself, and a one-to-one from Goal to Item? The only thing I would worry about here is circular references.
Also, read Relationships and Fetched Properties in the CoreData Programming Guide.
Here is how it is done:
You set up a to-many relationship from Goal to Item in the model editor. Don't use any ids, foreign keys etc. This is old-fashioned database thinking - you can forget about it. Here we are only dealing with an object graph. The database layer is just an implementation detail for persisting the data.
Make two more relationships in entity Goal to itself: a to-one called parent, a to-many called subGoals. Make them the inverse of each other. Simple!
QED is correct, you can create a to many relationship on goal (call it subgoals) as well as a to-one relationship on goal (call it parentGoal) and set them as inverses to each other.
Then create another to many relationship (call it items) on the goal entity, with the inverse being a to one relationship on the item entity (call it goal). Then you're all set. You don't need to link items with a unique id, just add them to the items relationship.
Also note that if you did want to give items a unique id, do not use the objectID. The objectID should only be used as a temporary id as they are not guaranteed to remain the same. In fact they will change if you ever do a Core Data migration.
One way, though not really great, is to create a another entity, say subGoal, and each goal has one subGoal and each object of subGoal has many goal.
i'm having some issues with core data, so i hope that someone will be able to help me :)
First problem, i have a data model that looks like this :
Entity P (A) <----> Entity R
/ | \
/ /\ \
/ / | \ \
C D E F G
All my entities inherit from the same entity "P" because they need a common attribute and a common relationship ("A" and "R")
The problem i am getting is that core data uses generates only one sqlite table for all the entities when you use inheritance. In my case it means that my database will have only 1 table for all the datas. I did some research and i saw that it creates performance issues (moreover all my entities attributes are transients and during willSave their values are aggregated+encrypted into one NSData stored in "A", so i won't be able to use predicate to filter and improve SELECT performances). So i decided to remove "P", and to add "A" into "C", "D"..., "G". The problem is with "R", because before i had only one inverse relationship in it, and now i need to create one each time i create a new kind of entity.
So i would like to remove all the inverse relationships, is it possible?
Sometimes i need to create managed object with a nil context, and i insert them into the context later, this is probably why the inverse relationship are not automatically set by core data if i set the non-inverse before the insertion in the MOC right ?
Anyway i never need the inverse, so can i avoid defining them even if i get a warning ?
2nd problem, in specific situations i need to create a new "R" and to assign it to "C", "D",.., "G" during the MOC save. So i would like to use willSave but, i don't know if the created entity will be saved. If the MOC does a simple loop over the "insertedObjects" / "updatedObjects" / "deletedObjects", and for each object it calls willSave, does the save, and then calls didSave, it means that i'm going to modify the array on which it is iterating, and then it should crash no?
As you and I both independently found out the hard way, be very, very careful with entities which inherit from each other. I too found Core Data tends to make one giant table containing all the fields for the base entity and all entities which derive from it, so any given entity contains the fields for every potential entity from its furthest ancestor downwards. Very, very slow and expensive.
I highly recommend only having the entity classes themselves inherit from each other, and mirroring the properties of the base class in all entities instead, without any actual inheritance in the managed object model itself.
Core data is not a wrapper around your sql tables. It deals with object graph and its persistence. SQLite store is just one way of persisting it. Check this up.
Prevent Core Data From Combining Entities into One Table