Slow inserts for CoreData many-to-many relationship
Ferdev,
Thank you for a well written question. It is clear you have thought carefully about your problem before asking for help. This helps everyone.
Core Data does not appear to use block operations when it saves. Hence, you are going to have performance issues there. The relationship setting though should be faster than you're seeing.(BTW, most of the performance issues are driven by the speed of flash memory. It is slow on iOS devices. Hence, prefetching to keep your MOC hot with your data is important. Bulk fetching is important.)
I make several observations:
Why is the A->B to-many relationship both indexed and ordered? The ordering will slow down your inserts. Does it also make sense to index a relationship?
Are you using the bulk relationship setters (-add<Key>:
)?
Are you fetching all 2000 of your entity B records before you set them to the entity A instance?
Even though this doesn't affect your insert performance, why does the delete rule from A->B cascade? You write above entity B doesn't change.
Andrew
Swift iOS : Insert data into related entities in CoreData
First Question: Do i also have to enter the instance of the Sales entity into the Sales Entity? or that will be updated automatically since there is a relationship?
Something you might not realize here is that you are inherently saving the object by adding it to the managedObjectContext
. As soon as you do something like
let sale = Sale(context: managedObjectContext)
followed by
managedObjectContext.save()
the context issues a save request to your persistent store (your actual SQL database).
Therefore your question whether you need to store the Sale as well is answered, it will always be stored upon saving the context.
Second Question: If i want to query all the sales that happened to date, do i query the Sales Entity? or do i query the relationship in the Products Entity?
That depends...
First let me give you a little tip/best practise:
Always make sure to set up an inverse relationship
In the Core Data Editor for your Product
entity's relationships you can do something like this:
Your sales relationships look something like this:
A relationship is nothing more but a dependency between two entities, therefore there is always an inverse relationship between two entities, make sure you hook them up as shown above.
Why am I telling you this ? Remember I mentioned it depends what entity you do your query on ? This is where it matters.
For example, if you want the Sale
for a given Product
, you would query the product itself (by querying its relationship called sale
):
let product = [A product instance from your Core Data store]
let sale = product.sale // returns the sale the product is associated to
If you want all the products from a given sale, you would query the Sale
entity leveraging the products
relationship:
let sale = [A sale from your Core Data store]
let products = sale.products // the products contained in the sale
You mentioned that you want all the sales to a given date:
It would not make any sense querying the Product
entity for that because each product only has a relationship to the sale it is contained in.
So, to answer your question, you should query the Sale
entity to retrieve all the sales to a given date.
I hope that helps, let me know if something is unclear.
Fetching a one-to-many core data relationship returns correct objects the first time but empty set all other times
I had a similar problem. The parent-child relationship worked when the app was running but after re-start only the latest child record was retrieved.
I was adding the children like this:
- create the child record
- set the child's parent attribute, set the child's other
attributes - add the child to the parent using the parent's add method
I found that it was fixed if I did it like this:
- create the child record
- add the child to the parent using the parent's add method
- set the child's parent attribute, set the child's other
attributes
Core data insert and fetch to-many relationship entities
Yes, you have made the opposite relationship. You have a team member having many teams and a team belonging to one member. You can tell by the arrows on the relationship line: the double arrow means 'has many' and the single arrow means 'has one' or 'belongs to' (read in the direction that the arrow is pointing).
You should switch the direction in the model navigator, trash the existing generated classes then re-generate them.
When you have the relationship set up correctly then you can use the generated accessors to add members to a team and retrieve members for a particular team.
EDIT to show example of adding a new team member to a team:
TeamMember *newTeamMember = [NSEntityDescription insertNewObjectForEntityForName:@"TeamMember" inManagedObjectContext:context];
newTeamMember.team = <existing team managed object>
It's as simple as that. Core Data will make sure that the reverse relationship is updated automatically, so the teamMembers collection of the team will include the new member you just added.
CoreData Relationship not updating after insert
Are you sure you're referencing the same entity1 object when you set the relationships? You can check by printing its URI representation when you fetch it in your table controller and when you do the import.
This may also be a result of using separate MOC instances to do the first fetch and the import (though that's the correct way to do it). It might help if you give some more detail about your import routine.
Update:
(Answered in the comments below). Bidirectional relationships need to be established in both directions. For example:
// set citation's owner
[citation setOwner:owner]; // or: citation.owner = owner;
// add citation to owner's citations
[owner addCitationsObject:citation];
Core Data: having issue inserting data with relationship
In this line:
requestCategory.predicate = NSCompoundPredicate.init(andPredicateWithSubpredicates: predicateArray)
you're creating a compound predicate with ANDs. You're asking Core Data to fetch you all of the categories that have id = 7 AND id = 8 AND ... etc. That's not going to work. The category can only have a single id. You actually want an 'or' predicate in this case.
However, I think the better way to do this is to load all of your categories into a dictionary keyed by their id before you start looping through your XML, and then just pull them out of the dictionary. That will be much more performant than fetching each time.
Also, you can't fetch categories in a separate context and then create relationships between objects from separate contexts. Core Data will crash if you try it.
How to fetch Specific Data in One to Many Core Data Relationships?
First...
Fix the naming of your relationships. As others have pointed out in comments on your other question, you have named them back to front: in the Person
entity, the to-many relationship to Account
should be named "accounts" not "person". Likewise in the Account
entity, the to-one relationship to Person
should be named "person" not "accounts".
Next...
Although you have defined the "accounts" relationship as to-many, the savePersonData
code in this question creates only one Account
and one Person
- but does not then set the relationship between them. (You can see this in your Output: each Account
has nil for its "accounts" relationship).
The code in your previous question did set the relationship (by adding the newAccount
to the relationship on the newPerson
object). In your code above you could use (after fixing the relationship names):
NSMutableSet *setContainer = [newDevice mutableSetValueForKey:@"accounts"];
[setContainer addObject:newAccount];
but with one-many relationships it is easier to set the inverse relationship:
[newAccount setValue:newDevice forKey:@"person"];
Next...
Your checkBalance
method correctly fetches any Person
objects whose "mobile_no" attribute matches. But your subsequent code then fetches ALL Account
objects - even if you had correctly set the relationship.
If you want only those Account
objects that are related to a given Person
, that is precisely what the "accounts" relationship represents. So you could just use that relationship to access the related Account
objects:
if(!([result count] == 0)) {
NSManagedObject *requiredPerson = (NSManagedObject *)result[0];
NSSet *temp = [requiredPerson valueForKey:@"accounts"];
for (NSManagedObject *object in temp) {
NSString *intValue = [object valueForKey:@"balance"];
NSString *alertString = [NSString stringWithFormat:@"%@",intValue];
[self displayAlertView:@"Available Balance" withMessage:alertString];
}
}
Alternatively, fetch the relevant Account
objects directly (without fetching the Person
object first) by specifying a predicate that traverses the relationship:
NSManagedObjectContext *managedObjectContext = appDelegate.managedObjectContext;
NSFetchRequest *newFetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Account"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"person.mobile_no = %@",self.textField.text];
[newFetchRequest setPredicate:predicate];
NSMutableArray *temp = [[managedObjectContext executeFetchRequest:newFetchRequest error:nil] mutableCopy];
for (NSManagedObject *object in temp)
{
NSString *intValue = [object valueForKey:@"balance"];
NSString *alertString = [NSString stringWithFormat:@"%@",intValue];
[self displayAlertView:@"Available Balance" withMessage:alertString];
}
Related Topics
Xcode 6 & Swift: Black Bars Appear Above and Below the Viewcontroller on iOS 7 iPhone 5 Device
Exc_Bad_Access Using Ibinspectable
Replaykit Startrecording Sometimes Never Enters Completion Handler
Include Pods in Main Target and Not in Watchkit Extension
Mpmovieplayercontroller Stops Playing After 5 Seconds - Swift
Embedding a Uitableview as a Container View Within a Uiviewcontroller
Uitableview Inside Uitableviewcell with Dynamic Height
Daily Local Notifications Are Not Working
How to Handle Oauth-Style Log Ins with Imessage Apps in iOS 10, Xcode 8
How to Change the Nstimeinterval of an Nstimer After X Seconds
Start/Stop Image View Rotation Animations
Multiple Iboutlets in Same Line of Same Type in Swift
Storyboard Reference to Cocoapods Storyboard Seems Broken
Buttonwithtype' Is Unavailable: Use Object Construction 'Uibutton(Type:)
Restkit, Coredata and Swift - I Can't Seem to Fetch Results Back Out