I have a problem with Core Data. I read around that Core Data is lazy to load entity relationships, in case this, has not a to-many relationship.
I have an entity "Item" which has a relationship (to-many relationship) with an entity "Movement".
In this method, addition to loading all instances of "Movement", I want to load the relative attributes of "Item", for example "name".
//Core data request
NSError *error;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Movement"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"date" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)]];
NSFetchedResultsController *result = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil
cacheName:#"Root"];
[result performFetch: &error];
to see if it works, I added this code:
NSArray *array = [NSArray arrayWithArray:[self.managedObjectContext executeFetchRequest:fetchRequest error:&error]];
for (int i = 0; i < array.count; i++) {
Movement *movement = [array objectAtIndex:i]
NSLog(#"item name %#",movement.movement_inItem.name);
}
the result is null item name (null)
I looked around, and tried to put this code under [fetchRequest setEntity:entity];
NSString *relationshipKeyPath = #"movement_inItem";
NSArray *keyPaths = [NSArray arrayWithObject:relationshipKeyPath];
[fetchRequest setRelationshipKeyPathsForPrefetching:keyPaths];
[fetchRequest setIncludesSubentities:YES];
but nothing changes.
Thanks a lot!
Related
I am using CoreData in my application. Everything is working fine except coredata is always returning max 20 records although i have more than 50 records. I have checked my code again and again but not finding the exact reason. I am also not using fetchLimit property. Kindly Help me.
Thanks.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:_manager.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = nil;
if (key != nil) {
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:key ascending:ascending];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
}
NSError *error = nil;
NSMutableArray *array = [[_manager.managedObjectContext executeFetchRequest:fetchRequest error:&error] mutableCopy];
return array;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSInteger rowCount = [context countForFetchRequest:fetchRequest error:&error];
fetchRequest.fetchLimit = rowCount;
NSArray *allItems = [context executeFetchRequest:fetchRequest error:&error];
Here rowCount will calculate actual count of all rows and you can set it as fetchLimit
Core Data returns 20 records by default. You can set records limit by using setFetchLimit of NSFetchRequest class.
NSFetchRequest* request = [[NSFetchRequest alloc] init];
[request setEntity:[...]];
[request setFetchLimit:50];
I have 1-many relationship and I am successfully putting data into it. The problem is that I am not able to fetch it out via the relationship attribute.
My ADD Code:
NSManagedObjectContext *context = [[CBICoreDataController sharedInstance] masterManagedObjectContext];
NSManagedObject *orders = [NSEntityDescription
insertNewObjectForEntityForName:#"UnsyncedOrders"
inManagedObjectContext:context];
[orders setValue:[dictionary valueForKey:#"specialInstructions"] forKey:#"specialInstructions"];
[orders setValue:[dictionary valueForKey:#"poNumber"] forKey:#"poNumber"];
[orders setValue:[dictionary valueForKey:#"specialInstructions"] forKey:#"specialInstructions"];
[orders setValue:[dictionary valueForKey:#"deliveryDate"] forKey:#"deliveryDate"];
[orders setValue:[dictionary valueForKey:#"account"] forKey:#"account"];
NSMutableSet *muteSet=[orders mutableSetValueForKey:#"items"];
for (NSDictionary *dict in [dictionary valueForKey:#"items"]) {
NSManagedObject *items = [NSEntityDescription
insertNewObjectForEntityForName:#"UnsyncedOrderItems"
inManagedObjectContext:context];
[items setValue:[dict valueForKey:#"arraykey"] forKey:#"arrayKey"];
//Other Sets Here
[muteSet addObject:items];
}
[orders setValue:muteSet forKey:#"items"];
NSError *error;
if (![context save:&error]) {
NSLog(#"Error saving in writeToMenuCostingDetailsTable: %#", [error localizedDescription]);
}
What I have for the fetch now but it does not work:
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"arrayKey" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSEntityDescription *parent = [NSEntityDescription entityForName:#"UnsyncedOrders"
inManagedObjectContext:context];
NSEntityDescription *child = [NSEntityDescription entityForName:#"UnsyncedOrderItems"
inManagedObjectContext:context];
[fetchRequest setEntity:child];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"orders == %#", parent];
[fetchRequest setPredicate:predicate];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
NSError *error;
[aFetchedResultsController performFetch:&error];
NSArray *fetchedObjects = [aFetchedResultsController fetchedObjects];
Your orders relationship relates to a specific instance of UnsyncedOrders. However when you try to perform a fetch, you do this:
NSEntityDescription *parent = [NSEntityDescription entityForName:#"UnsyncedOrders"
inManagedObjectContext:context];
[...]
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"orders == %#", parent];
[fetchRequest setPredicate:predicate];
You're trying to fetch instances where the orders relationship points to the UnsyncedOrders entity itself, not those that relate to a specific instance of UnsyncedOrders. That's always going to fail. In fact there's a good chance that if you were checking the result of performFetch: that it's returning NO and providing you with some sort of error describing the problem.
If you want to fetch the UnsyncedOrderItems that relate to a specific instance of UnsyncedOrders, you need to use a predicate that refers to a specific instance. However, if you already have that instance, you don't need to fetch-- just ask the UnsyncedOrders instance for the value of its items relationship.
This is the solution that I ended up using:
NSManagedObjectContext *context = [[CBICoreDataController sharedInstance] masterManagedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"UnsyncedOrders"
inManagedObjectContext:context];
NSError *error = nil;
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
for (UnsyncedOrders *info in fetchedObjects) {
[mutableArray addObject:info.items];
}
NSFetchRequest *fetchLLObjects = [[NSFetchRequest alloc] init];
[fetchLLObjects setEntity:[NSEntityDescription entityForName:#"CustomerOrder" inManagedObjectContext:self.managedObjectContext]];
[fetchLLObjects setIncludesPropertyValues:NO]; //only fetch the managedObjectID
NSError *error = nil;
NSArray *allObjects = [self.managedObjectContext executeFetchRequest:fetchLLObjects error:&error];
Here array is showing nil. But in database I could see that there are data. I don't know what might be the reason.
Please add your predicate in the fetchrequest
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"CustomerOrder"
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"managedObjectID == %#", managedObjectID]] inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
Set following 2 properties and you are done.
fetchRequest.returnsDistinctResults = YES;
fetchRequest.resultType = NSDictionaryResultType;
Hope this helps.
Edit
NSFetchRequest *fetchRequest= [[NSFetchRequest alloc]init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Songs" inManagedObjectContext:myManagedObjectContext];
//Take properties dictionary
NSDictionary *entityProperties = [entity propertiesByName];
[fetchRequest setEntity:entity];
[fetchRequest setReturnsDistinctResults:YES];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:[entityProperties objectForKey:#"song_type"]]];
NSArray * result = [myManagedObjectContext executeFetchRequest:fetchRequest error:nil];
You said: "But in database I could see that there are data."
I'm skeptical of that statement. I suspect that no CustomerOrder objects exist in the Core Data store. The only way to "see" the data inside the store is to turn off journaling mode and use 3rd party software to peak inside the .sqlite file.
Despite what others have said, your fetch request is fine. So double check your code where you insert objects into the store and save to the context.
In my ios project I use two entities (CoreData): Person and Gifts with To-Many Relationship
I know how to calculate the sum of gifts to one person:
NSDecimalNumber *orderSum=[person.gifts valueForKeyPath:#"#sum.priceOfGift"];
But how do I calculate the sum of all persons?
-(NSFetchedResultsController *) fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
//NSError *error = nil;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Person"
inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"nameOfPerson"
ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
_fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:#"nameOfGroup" cacheName:nil];
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
The "sum of all persons" would be to fetch all persons and count them
int sum = fetchedObjects.count;
But perhaps you mean the "sum of the prices of all gifts of all persons". If you think about it, it is the same as the sum of the prices of all gifts. Thus, you can just fetch the gifts and calculate
NSNumber *sum = [self.fetchedResultsController.fetchedObjects
valueForKeyPath:#"#sum.priceOfGift"];
You can try to fetch all the Persons, then use the sum
NSError *error = nil;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"Person" inManagedObjectContext:managedObjectContext];
request.predicate = nil;
request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"index" ascending:YES]];//some parameter
NSArray *persons = [managedObjectContext executeFetchRequest:request error:&error];
NSDecimalNumber *orderSum;
for (Person *person in persons)
orderSum = [NSDecimalNumber decimalNumberWithDecimal:orderSum.decimalValue
+[person valueForKeyPath:#"gifts.#sum.priceOfGift"].decimalValue]
Though, now work with NSDecimalNumber look a bit uncomfortable.
Here I got the value in fetchedObjects. How can I update the value in the array?
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Reserve" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
//NSSortDescriptor tells defines how to sort the fetched results
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"number" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSLog(#"sort count%d",[sortDescriptors count]);
fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(number = 100)", self.txtReserve.text];
// [fetchRequest setPredicate:predicate];
[fetchedResultsController.fetchRequest setPredicate:predicate];
self.fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSLog(#"Count of array::::%d",[fetchedObjects count]);
NSManagedObject *device = [fetchedObjects objectAtIndex:0];
NSLog(#"device::::%#",device);
I suggest that you read/watch some of the many books/tutorials on Core Data. You are missing a very basic understanding of the technology.
First, the objects you receive represent objects in the database, you have to know the entity descriptions to get the data. For example, the most basic way to get the "number" attribute of the "Reserve" entity would be...
[managedObject valueForKey:#"number"];
If you use Xcode (or a tool called mogenerator) you can have subclasses generated for your entities, and can more easily access the data via custom accessor methods.