Subquery Predicate Core Data - ios

I have two Entity models "Content" and "LessonsContent" with no relationship between them. Both entities have common attribute "contentID" of NSNumber type. I am fetching all contents objects from "Content" entity for given predicate and storing these objects in contents array. I was successful in doing so.
Now, I want to fetch all lessonsContent objects from "LessonsContent" entity whose contentIds are present in contents array.
I am using following code:
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"(contentType == %#)", #"Games"];
NSError * error;
NSFetchRequest * request = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([Content class])];
[request setPredicate:predicate];
[request setReturnsObjectsAsFaults:NO];
NSArray *contents = [[DELEGATE managedObjectContext] executeFetchRequest:request error:&error];
if(error){ NSLog(#"Error in fatching data");}
//predicate = [NSPredicate predicateWithFormat:#"Content.contentID IN %#", contents];
predicate = [NSPredicate predicateWithFormat:#"(SUBQUERY(contents, $x, $x.Content.contentID IN %#).#count != 0)",contents];
request = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([LessonsContent class])];
[request setPredicate:predicate];
NSArray * mappingArray = [[DELEGATE managedObjectContext] executeFetchRequest:request error:&error];
NSLog(#"mappingArray %#", mappingArray);
But app is crashing. Please suggest appropriate solution.
Thanks in advance.

You have to get an array of contentID's first. Then use IN.
NSArray *contents = [[DELEGATE managedObjectContext] executeFetchRequest:request error:&error];
NSArray * allContentIDs = [contents valueForKey:#"contentID"];
then use the second predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"contentID IN %#", allContentIDs];
[request setPredicate:predicate];
Hope this helps.

Related

Core data crash when fetching over 1000 objects

When I try to fetch more than 1000 NSManagedObjects from Core Data, my app crashes with this message:
error: (1) I/O error for database at .../Documents/Stores/Model.sqlite.
SQLite error code:1, 'Expression tree is too large (maximum depth 1000)'
CoreData: error: (1) I/O error for database at .../Documents/Stores/Model.sqlite.
SQLite error code:1, 'Expression tree is too large (maximum depth 1000)'
The code I use to fetch the objects selected by the user is this:
NSManagedObjectContext *context = cdh.context;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Spot" inManagedObjectContext:context];
NSError *error = nil;
[request setEntity:entity];
request.includesPropertyValues = NO;
NSMutableArray *subPredicatesArray = [NSMutableArray array];
for (NSString *string in uuidStrings)
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K like %#", #"sID", string];
[subPredicatesArray addObject:predicate];
}
NSCompoundPredicate *compoundPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:subPredicatesArray];
[request setPredicate:compoundPredicate];
NSArray *fetchedObjects = [context executeFetchRequest:request error:&error];
Is there a better way to fetch 1000+ objects that won't cause my app to crash?
Assuming the uuidStrings contain exact matches for the sID attribute, you should be able to replace the code with this (untested):
// remove subPredicatesArray, the loop and compoundPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"sID IN %#", uuidStrings];
[request setPredicate:predicate];

Unable to fetch specific column that from core data

I have created a an entity called Statutory with four columns namely name,complianceName,statMappingName,country
i want a get all complianceName names that matches a specific statMappingName. Following is my code
NSString *nameToGet = self.statNameArray[indexPath.row] ;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"complianceName = %#", nameToGet];
[fetch setPredicate:predicate];
NSLog(#"n %#",predicate);
NSError *error = nil;
NSArray *results = [[self managedObjectContext] executeFetchRequest:fetch error:&error];
if(results) {
NSLog(#"Entities with that name: %#", results);
} else {
NSLog(#"Error: %#", error);
}
But it is not providing the compliance name specific to that statMappingName. How can I be able to get all complianceName that has a specific statMappingName?
Try this:-
NSString *firstName = statMappingName;
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"firstName == %#", firstName]];
If you want to fetch specific column from core data
You can use the below method:-
NSEntityDescription *entity = [NSEntityDescription entityForName:entityname inManagedObjectContext:self.managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setReturnsObjectsAsFaults:NO];
[request setEntity:entity];
[request setFetchLimit:1];
[request setPredicate:[NSPredicate predicateWithFormat:#"(complianceName LIKE %#)",nametoGet]];
NSError *error = nil;
NSMutableArray *tempDataArr = [[self.managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
Note:-
*entityname: Your entity name
*self.managedObjectContext : Your managedobjectcontext
To Get All compliance Name use the below method
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:entityName];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSMutableArray *tempDataArr =[NSMutableArray new];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"(ANY complianceName LIKE %#)",nametoGet]];
tempDataArr = [[self.managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
try these code for contains statMappingName
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"complianceName contains[c] %#", statMappingName];

Filter title from core data

I have an entity that has title title and amount. I would like to display the total value I have for each title in my entity.
You can pretty much dispense with fetch requests by leveraging KVC (Key-Value-Coding).
First fetch (or filter) with this predicate:
[NSPredicate predicateWithFormat:#"category = %#", #"Food"];
Then just sum up the result in one line:
NSNumber *sum = [result valueForKeyPath:#"#sum.amount"];
There is no need to fetch only certain attributes using NSDictionaryResultType - just fetch the normal NSManagedObjects (Core Data will optimize for you).
You use NSPredicate to filter your objects by category and then you can fetch only the values of a certain property e.g.:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// Entity
NSEntityDescription *ent = [NSEntityDescription entityForName:#"Incoming" inManagedObjectContext:context];
[request setEntity:ent];
// Predicate
NSPredicate *pred = [NSPredicate predicateWithFormat:#"category MATCHES[cd] %#", #"FOOD"];
[request setPredicate:pred];
// Property fetch
[request setResultType:NSDictionaryResultType];
[request setReturnsDistinctResults:NO];
[request setPropertiesToFetch:#[#"Amount"]];
// Execute the fetch.
NSError *error;
NSArray *objects = [context executeFetchRequest:request error:&error];
int total = 0;
if (objects) {
for(NSDictionary *dict in objects) {
NSString *key = dict.allKeys.lastObject;
total += [dict[key] intValue];
}
} else {
NSLog(#"Fetch error: %#", error.localizedDescription);
}
NSLog(#"Total: %i", total);
The following will get the categories and the sum in one fetch operation:
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Incoming"];
fetchRequest.resultType = NSDictionaryResultType;
NSExpression *sumExp = [NSExpression expressionWithFormat:#"sum:(amount)"];
NSExpressionDescription *sumED = [[NSExpressionDescription alloc] init];
sumED.name = #"sum";
sumED.expression = sumExp;
sumED.expressionResultType = NSDoubleAttributeType;
fetchRequest.propertiesToFetch = [#"title", sumED];
fetchRequest.propertiesToGroupBy = [#"title"];
NSArray *dictionaries = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
See the NSExpression documentation here.

Retrieving all the NSSet element values in a one to many relationship

I have a one to many relationship as shown in the attached image. I want to list down all the course titles a particular lecturer teaches and the solution i have come up so far is as follows.
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Lecturer"];
NSMutableSet *courseList = [[NSMutableSet alloc] init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == 'smith'"];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *lecturers = [self.managedObjectContext executeFetchRequest:request
error:&error];
for (Lecturer *lecturer in lecturers)
{
NSSet *set = lecturer.courses;
for (Course *course in set)
{
[courseList addObject:course.title];
}
}
The courseList object contains all the courses a given lecturer teaches.
IS there a better way to do this using nspredicates alone and not by using 2 for loops ?
Thanks in advance.
You can just fetch the Course objects directly, but specifying a different predicate that requires their authorname.name to match:
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:#"Course"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"authorname.name == 'smith'"];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *courseList = [self.managedObjectContext executeFetchRequest:request error:&error];
If you want an array with just the titles, you can then use:
NSArray *courseTitles = [courseList valueForKeyPath:#"title"];

NSPredicate over different entities

I want to make NSPredicate over different entities. Here is my core database.
To make it simple, this is the query I should do.
Select c.c_name From Company c, Person p Where c.c_id = p.cu_company_id
Now I was wondering how my predicate should look like if I want to achieve the result like the query above.
Assuming that c_id and cu_company_id are integers, you can try
NSFetchRequest *fr = [[NSFetchRequest alloc] initWithEntityName:#"Person"];
NSError *error;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"cu_company_id == data.company.c_id"];
[fr setPredicate:predicate];
NSArray *persons = [self.managedObjectContext executeFetchRequest:fr error:&error];
and once you have persons array, you can then loop through it and get the person's name. To get it the other way around
NSFetchRequest *fr = [[NSFetchRequest alloc] initWithEntityName:#"Company"];
NSError *error;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"c_id == data.person.cu_company_id"];
[fr setPredicate:predicate];
NSArray *companies = [self.managedObjectContext executeFetchRequest:fr error:&error];
and once you have companies array, you can then loop through it and get the company's name.

Resources