Core Data Taking Time to Insert Records with Fetching Entity & Set as Relationship

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:

Sample Image

Your sales relationships look something like this:

Sample Image

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



Leave a reply



Submit