exclude a property in NSFetchRequest - objective-c

I need to fetch an entity with all properties expect one property. I know that there is way to include name of all properties to do such a thing:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setResultType:NSDictionaryResultType];
[request setPropertiesToFetch:
[NSArray arrayWithObjects:#"property1", #"property2", /* etc. */ nil]];
NSEntityDescription *e = [NSEntityDescription entityForName:entityName
inManagedObjectContext:self.context];
But I don't want to mention all of properties because of one property!
Do you know any good performance solution for this?

Unfortunately you're going to have to name all properties except the one. There is no other way. Here is a way to do it automatically and don't worry about performance.
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:entityName inManagedObjectContext:self.context];
NSArray *allProperties = entityDescription.properties;
NSMutableArray *propertiesToFetch = [NSMutableArray arrayWithCapacity:allProperties.count];
for (NSPropertyDescription *property in allProperties) {
if (![property.name isEqualToString:#"xxx"]) {
[propertiesToFetch addObject:property];
}
}
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];
request.resultType = NSDictionaryResultType;
request.propertiesToFetch = propertiesToFetch;

You can use this approach to remove a particular property from an array of all the properties. Let's assume your Entity is called PatientRecord.
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setResultType:NSDictionaryResultType];
PatientRecord *patient;
NSMutableArray *allProperties = [[NSMutableArray alloc] initWithArray:patient.entity.properties];
[allProperties removeObject:#"propertyToRemove"];
[request setPropertiesToFetch:allProperties];
NSEntityDescription *e = [NSEntityDescription entityForName:entityName
inManagedObjectContext:self.context];

Related

Decrypting core data

Warning: I don't know obj C but was handed this project for this one task
I am successfully encrypting the fields which lay in core data (sqlite) but I cannot decrypt them using a similar method. Below is my code which is causing the app to break during the fetch of core data:
NSManagedObjectContext *context = [self getContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:entityName inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
[request setReturnsObjectsAsFaults:NO];
if (predicate != nil) {
[request setPredicate:predicate];
}
NSError *error;
//the code that breaks
NSMutableDictionary *theFetch = [[context executeFetchRequest:request error:&error] mutableCopy];
return [[self decryptDictionaryData:theFetch withUserId:entityDesc.propertiesByName[#"theUnlockKey"]] mutableCopy];
decryptDictionaryData goes through each key in the dictionary and decrypts as follows:
decryptedResult = [RNDecryptor decryptData:[[NSData alloc] initWithBase64EncodedString:value options:0]
withSettings:kRNCryptorAES256Settings
password:key
error:&error];

an NSPredicate for selecting a row with maximum value by group

I'm using Core Data to store entities in the form
TrackerEntry
username
timestamp
I want to select the latest record for each user. Using sql it would be something like
SELECT MAX(timestamp) FROM Log GROUP BY username
Is there anyway to create an NSPredicate to do this?
I would do it using NSExpression. This bit of code below won't work for you because you will have to group by username too, but it's a start for the best way of doing this without having to fetch everything. You want to perform the max and group in the db, not in memory - as it will be faster:
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
// Expression for the max
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:#"timestamp"];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName
inManagedObjectContext:self.coreDataStack.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setResultType:NSDictionaryResultType];
NSExpression *valueSumExpression = [NSExpression expressionForFunction:#"max:" arguments:[NSArray arrayWithObject:keyPathExpression]];
NSExpressionDescription *expressionDescription = [[[NSExpressionDescription alloc] init] autorelease];
[expressionDescription setName:#"maxTimestamp"];
[expressionDescription setExpression:valueSumExpression];
[expressionDescription setExpressionResultType:NSDecimalAttributeType];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];
// Filter
//NSPredicate *pred = [NSPredicate predicateWithFormat:#" your predicate here"];
//fetchRequest.predicate = pred;
NSArray *results = [self.coreDataStack.managedObjectContext executeFetchRequest:fetchRequest error:nil];
if([results count] == 0) {
} else {
// [[results objectAtIndex:0] valueForKey:#"maxTimestamp"];
}
This worked for me, but it is a loop. First you have to get the unique names into an array.
NSFetchRequest *nameRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Log" inManagedObjectContext:self.managedObjectContext];
nameRequest.entity = entity;
nameRequest.resultType = NSDictionaryResultType;
[nameRequest setPropertiesToFetch:[NSArray arrayWithObject:[[entity propertiesByName] objectForKey:#"name"]]];
NSArray *allNames = [self.managedObjectContext executeFetchRequest:nameRequest error:nil];
names = [allNames valueForKeyPath:#"#distinctUnionOfObjects.name"];
[nameRequest release];
NSLog(#"%#", names);
Not very efficient or convenient. After all, Core Data is not a database but an object graph.
Then you can loop through these and fetch just the top one.
NSMutableArray *mutableResults = [NSMutableArray array];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"Log" inManagedObjectContext:self.managedObjectContext];
NSSortDescriptor *numberSort = [NSSortDescriptor sortDescriptorWithKey:#"number" ascending:NO];
request.sortDescriptors = [NSArray arrayWithObject:numberSort];
request.fetchLimit = 1;
for (NSString *s in names) {
NSPredicate *pred = [NSPredicate predicateWithFormat:#"name = %#", s];
request.predicate = pred;
NSArray *results = [self.managedObjectContext executeFetchRequest:request error:nil];
[mutableResults addObject:[results objectAtIndex:0]];
}
[request release];
NSLog(#"%#", mutableResults);

Fetch Relationship Objects

CoreData beginner
I have a simple problem with CoreData. My model has two entities, now called A and B. Entity A has a to many relationship of B entities, which has a inverse relationship to entity A.
I'm retrieving entities A with this code:
NSManagedObjectContext *context = [self managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"A"
inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"name"
ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:descriptor]];
NSError *error = nil;
NSArray *items = [context executeFetchRequest:request error:&error];
if (error) /* ... */;
for (id item in items)
{
/* ... */
}
[request release];
[descriptor release];
Now I'd like to retrieve, inside that loop, an array of all the objects B pointed by the relationship of A. How can I achieve this? Should I create another fetch request or there is a more practical way?
I've searched StackOverflow and found similar questions, but too vague sometimes.
NSFetchRequest has an instance method on it called -setRelationshipKeyPathsForPrefetching:.
This method takes an array of key names that will be used to prefetch any objects defined in relationships with those key paths. Consider your example, updated with the new code:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
NSString *relationshipKeyPath = #"bObjects"; // Set this to the name of the relationship on "A" that points to the "B" objects;
NSArray *keyPaths = [NSArray arrayWithObject:relationshipKeyPath];
[request setRelationshipKeyPathsForPrefetching:keyPaths];
Now once you complete your fetch request, all of those relationship objects should be faulted in and ready to go.

How to load all instances of entity / property?

i have some Data in a TableView (loaded from coreData) and now i want to upload this data to a webserver.
Before i can do that i want to save all data to a *.txt file.
How can i load all instances of an entity / property to an mutable array?
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"barCode" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
Thanks,
brush51
Edit 1:
Can you give me a little Help (i dont want ALL data, just the property "barCode"), now i have this code:
NSManagedObjectContext *moc = [self managedObjectContext];
NSFetchRequest *req = [[NSFetchRequest alloc] init];
[req setEntity:[NSEntityDescription entityForName:#"Event" inManagedObjectContext:moc]];
[req setIncludesPropertyValues:NO];
NSError *error;
NSArray *codes = [moc executeFetchRequest:req error:&error];
[req release];
for (NSManagedObject *Event in codes) {
NSLog(#"there it is : ------------> %#", codes);
NSLog(#"barcodes ------------------> %#", [[managedObject valueForKey:#"barCode"] description]);
}
How to output ONLY the instances of the property "barCode" ??
thanks for answering,
here is my code:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"barCode" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
I have no predicate... Predicate is for what?
If you do a fetch request on the entity without a predicate, you'll get all the instances.

CoreData Fetch Request with Most recent Predicate

I have an Entity "Event" which contains a NSDate attribute named "AccidentDate". I am trying to do a fetch request to grab only the most recent 'AccidentDate' but I am not sure how to set up the predicate to grab only the last 'AccidentDate'
Below is my code so far...
NSFetchRequest *fetchRequest1 = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:self.managedObjectContext];
[fetchRequest1 setEntity:entity];
NSPredicate *predicate; //unknown code here
[fetchRequest1 setPredicate:predicate];
NSArray *items = [self.managedObjectContext executeFetchRequest:fetchRequest1 error:&error];
[fetchRequest1 release];
Any help would be greatly appreciated. Thanks
You can apply an array of sort descriptors directly to the NSFetchRequest and you can further set its fetch limit to 1. That creates the following code:
NSFetchRequest *fetchRequest1 = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest1 setEntity:entity];
NSSortDescriptor *dateSort = [[NSSortDescriptor alloc] initWithKey:#"accidentDate" ascending:NO];
[fetchRequest1 setSortDescriptors:[NSArray arrayWithObject:dateSort]];
[dateSort release], dateSort = nil;
[fetchRequest1 setFetchLimit:1];
NSManagedObject *latest = [[[self managedObjectContext] executeFetchRequest:fetchRequest1 error:&error] lastObject];
[fetchRequest1 release], fetchRequest1 = nil;
I would fetch all Events sorted by AccidentDate with no predicate and grab the first one from the array.