after i add new data in core data collection it can't be saved (multiply validation error occured) - core-data

The code bellow add to Core data issues, but after it added, I can't save with error (multiply validation error occured)
MySQLIXC *ixcDatabase = [[MySQLIXC alloc] init];
NSArray *destinationsForSaleList = [ixcDatabase destinationsForSaleList:carrier];
NSFetchRequest *request1 = [[[NSFetchRequest alloc] init] autorelease];
[request1 setEntity:[NSEntityDescription entityForName:#"DestinationsList"
inManagedObjectContext:managedObjectContext]];
for (NSDictionary *destinationsForSale in destinationsForSaleList) {
NSManagedObject *object1 = [NSEntityDescription
insertNewObjectForEntityForName:#"DestinationsList"
inManagedObjectContext:managedObjectContext];
NSLog(#"Moc: %#",managedObjectContext);
[object1 setValue:#"y" forKey:#"weAreSoldIt"];
// changeDate
NSString *chdate = [destinationsForSale objectForKey:#"chdate"];
NSDateFormatter *changeDate = [[[NSDateFormatter alloc] init] autorelease];
[object1 setValue:[changeDate dateFromString:chdate] forKey:#"changeDate"];
NSLog(#"Carrier :%# Destination name:%#",carrier, destinationsForSale);
//Country
[object1 setValue:[destinationsForSale objectForKey:#"country"] forKey:#"country"];
//rate
NSNumberFormatter *rate = [[[NSNumberFormatter alloc]init ]autorelease];
[object1 setValue:[rate numberFromString:[destinationsForSale objectForKey:#"price"]] forKey:#"rate"];
Unfortunately I can't fix a bug by the way which u propose bellow.
Bcs Entity DestinationList must have relations with Entity Carriers by project understanding.
That is how I try to fix it:
[objectDestinationList setValue:objectCarrier forKey:#"carrier"];
I was send to method my carrier object as object, but it doesn't work.
In this case, I don't know how is a way to fix it around. Bcs I see error, but don't see case why error is start.
Do u know a simple code to correct add relationships to Entity? All what I catch around internet is a core data book ,my Marcus Zarra and his very hard to understanding example. His showing a complex solution, I can understand it, but using programming style which not very easy for me at this moment (according my one month experience in cocoa programming ;)
Here is additional information: How I create Carrier instance. I have managedObjectContext, which I receive to class from AppDelegate.
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:#"Carrier"
inManagedObjectContext:managedObjectContext]];
NSManagedObject *carrier = [managedObjectContext executeFetchRequest:request error:&error]
by the same way I prepare NSManagedObject for DestinationsList Entity.
After that I add all values to NSManagedObject for destinationsList, I have to make relationship between Carrer NSManagedObject and destinationsList. In this case I have trouble. Bellow is how I try to update relationship for Carrier entity:
NSSet *newDestSet = [NSSet setWithObjects:objectDestination,nil];
[objectCarrier setValue:newDestSet forKey:#"destinationsList"];
finally I have 2010-11-03 21:22:56.968 snow[20301:a0f] -[NSCFArray initialize]: unrecognized selector sent to instance 0x1c44e40
Bellow is my class interface deescription:
#interface InitUpdateIXC : NSObject {
NSInteger destinationType;
}
-(void) updateCarrierList:(NSManagedObjectContext *)managedObjectContext;
-(void)updateDestinationList:(NSManagedObjectContext *)managedObjectContext
forCarrier:(NSString *)carrierName
forCarrierObject:(NSManagedObject *)objectCarrier
destinationType:(NSInteger)destinationType;
#end
Yep, bellow in answer present correct model, but some different is here.
At first, i don't have separate class for Entity as u present in you model. My current class is just NSManagedObject
In second, relationship "carrier" is non-optional for Entity DestinationsList.
SOLUTION AND ERROR DESCRIPTION:
In case of trouble, what happened with my code:
When i try to add setValue forKey with back relationship from DestinationsList to Carrier, i forget that NSManagmentObject return every time array, not just object.
This is a reason why i receive error about array init problem.
Solution is not sent Carrier object to method, bcs for me was too hard to extract from array correct object without key value. I was using a predicate access to extract object to array and lastObject function to extract correct object from array. After that i set accroding value and everything working fine.
A solution not look like cocoa-style, so better way is refactor it in future, any suggestion wellcome.
Here is appropriate code:
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:#"Carrier"
inManagedObjectContext:managedObjectContext]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name =%#",carrierName];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *currentCarriers = [managedObjectContext executeFetchRequest:request error:&error];
[objectDestination setValue:[currentCarriers lastObject] forKey:#"carrier"];

Try adding something like this for you 'save'
NSError *error = nil;
if (![managedObjectContext save:&error])
{
// Handle the error.
NSLog(#"Failed to save to data store: %#", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0)
{
for(NSError* detailedError in detailedErrors)
{
NSLog(#" DetailedError: %#", [detailedError userInfo]);
}
}
else
{
NSLog(#" %#", [error userInfo]);
}
}
At least, then you can see what the multiple errors are. If you post those, someone may be able to offer more help.
One thought, though, is that there is something buggy about your data model - like non-optional attribute with no value, etc.
If you create NSManagedObject subclassed Carrier and DestinationsList, then in Carrier.h you should have some method declarations like this. (Assuming that Carrier to-many DestinationsList is called 'destinationsLists'.)
#interface Carrier (CoreDataGeneratedAccessors)
- (void)addDestinationsListsObject:(Run *)destinationsList;
- (void)removeDestinationsListsObject:(Run *)destinationsList;
- (void)addDestinationsLists:(NSSet *)destinationsLists;
- (void)removeDestinationsLists:(NSSet *)destinationsLists;
#end
Once these are declared, you should be able to add a DestinationsList to a Carrier with a line like this:
[myCarrier addDestinationsListsObject:myDestinationsList];
Not seeing your full data model, it is difficult to know what is happening and what would help fix it.
Do you have something like this for your model definition?

Related

Saving array of images in core data as transformable

I want to add my imageArray into coredata as transformable but this is not storing properly.
My save button coding.
- (IBAction)saveButton:(id)sender {
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *newEntry = [NSEntityDescription insertNewObjectForEntityForName:#"FoodInfo" inManagedObjectContext:context];
NSAttributeDescription *messageType = [[NSAttributeDescription alloc] init];
[messageType setName:#"photos"];
[messageType setAttributeType:NSTransformableAttributeType];
[imagesForShow addObject:messageType];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Unable to save context for class" );
} else {
NSLog(#"saved all records!");
[context save:nil];
}
//[newEntry setValue:imagesForShow forKey:#"images"];
}
Here 'imagesForShow' is my array of images.
When iam going to fetch this image array , this showing nil
- (void)viewDidLoad {
[super viewDidLoad];
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:#"FoodInfo"];
[request setReturnsObjectsAsFaults:NO];
arrayForPhotos = [[NSMutableArray alloc]initWithArray:[context executeFetchRequest:request error:nil]];
// Do any additional setup after loading the view.
}
What I am doing wrong with this code. Thanks.
In your save code:
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *newEntry = [NSEntityDescription
insertNewObjectForEntityForName:#"FoodInfo"
inManagedObjectContext:context];
NSAttributeDescription *messageType = [[NSAttributeDescription alloc] init];
[messageType setName:#"photos"];
[messageType setAttributeType:NSTransformableAttributeType];
[imagesForShow addObject:messageType];
I can't even figure out what this is supposed to do. It's completely wrong. You should never be allocating an instance of NSAttributeDescription unless you are constructing a Core Data model on the fly-- which you are not doing and which almost nobody ever does. Creating the new entry is OK. The rest, I don't know. You said that imagesForShow is your array of images, so I don't know why you're also adding an attribute description to the array.
In a more general sense, if newEntry has a transformable attribute named photos and imagesForShow is an NSArray of UIImage objects, then you could do this:
[newEntry setValue:imagesForShow forKey:#"photos"];
This is similar to a line that you have commented out, though it's not clear why it's commented out.
But whatever you do get rid of the code creating the NSAttributeDescription.

Saving Core Data related data and retrieving with NSPredicate and NSFetchedResultsController with multiple entities

I'm fairly new to Core Data and am still trying to understand accessing and filtering related data. My problem is either I'm not getting the data correctly into the managedObjectContext or I'm not pulling it out correctly. (I think the first, but I'm not sure.)
Here's my data model with two entities related one to many: (I plan to refactor once I get one level of relationship working.)
I have a SeasonsVC in which you click on a season name and the list of games for that season is supposed to appear in the GamesVC and you have the option to add or edit an existing game. This works fine at a first pass. I can add and edit games via this code in the GameDetailsVC:
-(IBAction)done:(UIBarButtonItem *)sender {
Game *game = nil;
if (self.gameToEdit != nil) {
game = self.gameToEdit;
NSLog(#"Hitting gametoedit");
} else {
game = [NSEntityDescription insertNewObjectForEntityForName:#"Game" inManagedObjectContext:self.managedObjectContext];
NSLog(#"Hitting new game");
}
game.opponent = self.opponentTextField.text;
//season.seasonDescription = self.seasonDescriptionTextView.text;
NSLog(#"Game to edit: %#", game.opponent);
//NSLog(#"Season: %#", season);
//NSLog(#"MOC in done: %#", self.managedObjectContext);
//NSLog(#"Season name: %#", season.seasonName);
[self dismissViewControllerAnimated:YES completion:nil];
}
I can then see the games in the GamesVC via the fetchedResultsController and delegate methods, but each game is associated with every season. Once I try to filter the data with a predicate so that I only see the games that were added for that season all the games disappear. Here's the code for that from the GamesVC:
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Game" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSLog(#"Season name for predicate %#", self.season.seasonName);//shows correct season name
NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"season.seasonName like '%#'", self.season.seasonName]];
[fetchRequest setPredicate: predicate];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"dateOfGame" ascending:NO] ;
[fetchRequest setSortDescriptors:#[sortDescriptor]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil
cacheName:#"Root2"];
self.fetchedResultsController = theFetchedResultsController;
self.fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
Since I can log the correct season name right before the predicate statement, I think that the added games are not getting "associated" with the correct season when I put them in the MOC in the done: method shown above; otherwise, I'd expect the predicate to find them.
Can you help this rookie? Thanks.
A day later I have this sorted. I needed to make three changes to what I was doing.
First, in my prepareForSegue in my GameListVC I needed to pass the season along to the GameDetailsVC by changing the code to this. (Just added the one line: controller.season = self.season)
//pass the Season object to be edited
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
Game *gameToEdit = [self.fetchedResultsController objectAtIndexPath:indexPath];
controller.gameToEdit = gameToEdit;
controller.season = self.season;
Second, I had to put the new/edited game object into the MOC by adding these two lines to my done: method in the GameDetailsVC.
NSMutableSet *games = [self.season mutableSetValueForKey:#"games"];
[games addObject:game];
Third, I needed to simplify my predicate statement in my fetchedResultsController method in the GameListVC.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"season.seasonName like %#", self.season.seasonName];
So, to answer my own question, I was both not saving the game linked to the season and my predicate was wrong.
I hope some of this helps another rookie.

Core Data one to many record insert error

I have three entities
Forms{
name:string
jobs<-->>JSAjobs.form
}
JSAjobs{
name:string
form<<-->Forms.jobs
}
Jobs{
step:string
jobs<<-->Forms.jobs
}
I am getting this error:
to-many relationship fault "jobs" for objectID 0x95afe60. . . fulfilled from database. Got 0 rows
Now I save the row for Forms entity first later on I need to fetch the last record on the Form entity create a new row on JSAjobs with details on JSAjop like next
Thanks
NSMutableArray *jobData = [[NSMutableArray alloc]initWithArray:controller.jobData];
NSManagedObjectContext *context = [self managedObjectContext];
NSError *error;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"JSAform" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *testForFalse = [NSPredicate predicateWithFormat:#"emailed == NO"];
[fetchRequest setPredicate:testForFalse];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
NSLog(#"Fetched Rows: %i", [fetchedObjects count]);
//NSManagedObject *existingParent= //... results of a fetch
JSAform *lastForm = [fetchedObjects objectAtIndex:0];
JSAjobs *newJobs = [NSEntityDescription insertNewObjectForEntityForName:#"JSAjobs" inManagedObjectContext:context];
// Setting new values
newJobs.jobType = [NSString stringWithFormat:#"%#", [jobData objectAtIndex:0]];
newJobs.jobName = [NSString stringWithFormat:#"%#", [[[jobData objectAtIndex:1]objectAtIndex:0] objectAtIndex:0]];
newJobs.comments = [NSString stringWithFormat:#"%#", [[[jobData objectAtIndex:1]objectAtIndex:0] objectAtIndex:1]];
newJobs.date = [NSDate date];
[newJobs setValue:lastForm forKey:#"form"];
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
//New SOP Value
JOBsop *jobSOP = [NSEntityDescription insertNewObjectForEntityForName:#"JOBsop" inManagedObjectContext:context];
for (int i = 0; i< [[jobData objectAtIndex:1]count]; i++){
NSLog(#"Value for key: %i", i);
if (i > 0){
for (int k = 0; k< [[[jobData objectAtIndex:1]objectAtIndex:i] count]; k++){
jobSOP.step = [[[jobData objectAtIndex:1]objectAtIndex:i] objectAtIndex:k];
[jobSOP setValue:newJobs forKey:#"jobs"];
// [NSNumber numberWithInt:[txtBoots.text integerValue]];
NSLog(#"Simple key: %#", [[[jobData objectAtIndex:1]objectAtIndex:i] objectAtIndex:k]);
}
}
}
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
enter code here
Your entities are very confusing because you did not pick usable entity names. You were too confused to lay out these simple relationships yourself. This results in chaotic code and does not allow you to think things through in a structured way.
Your code is completely incomprehensible. You have a data array despite a fetched results controller (presumably). The second part of your code sports a mysterious and cryptic new entity JOBsob. No way you can ask a meaningful question like this, let alone get an answer.
You have nested arrays without any type checking which is bound to break and in any way completely impossible to debug. Get rid of all of these.
Nevertheless, let's five it a try to get you started:
First, it does not make sense to use the plural for the entity name. If the entity represents a "form", it should be Form not Forms.
Maybe you want this setup:
Form <<----> Job <----->> JobDetail
One job has many forms and many job details. So the Form has a relationship job while the Job has a relationship forms. Similarly, a Jobdetail has a relationship job while Job has a relationship details.
When you have a form and create a new job you can only assign one job to it. Thus, the old job (if any) relationship would be broken.
oldForm.job = newJob;
This is a much safer way to assign relationships. Of course, you have created NSManagedObject subclasses for these entities for this purpose.
If however, the relationship between Job and Form is one-to-many in the other direction, your scheme would look like this.
Form <---->> Job <------>> JobDetail
I do not really now what a "form" would mean in this case - I will just rename it Project for clarity.
Project <---->> Job <------>> JobDetail
Now you can assign the a new job to a project and link the other relationships like this:
newJob.project = existingProject;
newJobDetail.job = newJob;

How do I check if an NSSet contains an object of a kind of class?

How would you implement the following instance method for NSSet:
- (BOOL)containsMemberOfClass:(Class)aClass
Here's why I want to know:
Core Data model:
How do I add a Facebook authorization to a user's authorizations NSSet, but only if one doesn't already exist. In other words, a user can have many authorizations (in case I choose to add a Twitter (e.g.) authorization in the future) but should only have one of each kind of authorization. So, if (![myUser.authorizations containsMemberOfClass:[Facebook class]]), then add a Facebook authorization instance to myUser.
Unfortunately, you have to loop through all of the authorizations and check:
#interface NSSet (ContainsAdditions)
- (BOOL)containsKindOfClass:(Class)class;
- (BOOL)containsMemberOfClass:(Class)class;
#end
#implementation NSSet (ContainsAdditions)
- (BOOL)containsKindOfClass:(Class)class {
for (id element in self) {
if ([element isKindOfClass:class])
return YES;
}
return NO;
}
- (BOOL)containsMemberOfClass:(Class)class {
for (id element in self) {
if ([element isMemberOfClass:class])
return YES;
}
return NO;
}
#end
With Core Data it is actually best practice to use an NSFetchRequest with an NSPredicate. To do that you would have to add an attribute to your Authorization object, something like authorizationType. You could then do the following:
NSManagedObjectContext *moc = [self managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY user.authorizations.authorizationType == %#", #"facebook"];
[request setEntity:[NSEntityDescription entityForName:#"Authorization" inManagedObjectContext:moc]];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *result = [moc executeFetchRequest:request error:&error];
You can then check the count of result to see if it exists or not. Using NSPredicate allows you to use any optimizations Apple has added around CoreData. Here are the Apple Docs.
What if you add this instance method to the User class?
- (BOOL)hasFacebookAuthorization {
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"user.id == %#", [self id]];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"Facebook"
inManagedObjectContext:managedObjectContext]];
[fetchRequest setPredicate:predicate];
NSError *error;
NSArray *result = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (!result) {
// TODO: Handle the error appropriately.
NSLog(#"hasFacebookAuthorization error %#, %#", error, [error userInfo]);
}
return [result count] > 0;
}
Your going about this the wrong way. If the types of authorization are something common and important then you should model that in your data model directly instead of trying to impose that structure in external controller code.
If you have a fixed set of authorizations then you should create an entity to model those authorizations.
Facebook{
accessToken:string
experationDate:date
authorization<-->Authorizations.facebook
}
Google{
username:string
password:string
authorization<-->Authorizations.google
}
Authorizations{
user<-->User.authorizations
facebook<-->Facebook.authorization
google<-->Google.authorization
}
Now you have all your authorizations captured in the data model where they belong. To tighten things up more. You could add a custom method to the User class to control adding and removing authorizations.
The key idea here is that all the logic that manages data should be encapsulated in the data model to the greatest extent possible. This allows you to (1) test all data operations independent of the interface and (2) easily add and remove interface elements without breaking the data model.
Old question, but slightly different answer:
NSPredicate *objectTypeFilter = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return [evaluatedObject isKindOfClass:NSClassFromString(#"MyObject")];
}];
NSSet *myObjects =[allObjects filteredSetUsingPredicate:objectTypeFilter];
if (myObjects.count>0) {
// There was at least one object of class MyObject in the allObjects set
}

Core data max value for property of entities children

I know I shouldn't look at Core Data as something relational. But with a SQL query it is easiest to explain what I'm trying to do.
What I'd like to do is get the max value from a property constrained to the children of an entity. In SQL something like: select max(valueY) from graphdata where parentID = 10
I'm doing something akin to the above SQL query successfully excluding the where (NSPredicate) part.
I added the NSPredicate to my code thinking it would exclude the graphdata objects not within the KPI I'm looking at. Well, guess not, it's not what I'm seeing, it seems to do nothing at all really.
The Core Data Model consistst of multiple KPI objects, each containing an Array of GraphData objects. Every GraphData object contains a valueX and a valueY property.
I want the max valueY for the graphdata of a specified KPI object.
Here's my code, it's based on one of Apple's core data snippets:
NSManagedObjectContext *context = ...
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:GRAPH_DATA_ENTITY_NAME inManagedObjectContext:context];
[request setEntity:entity];
// Specify that the request should return dictionaries.
[request setResultType:NSDictionaryResultType];
// Create an expression for the key path.
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:#"ValueY"];
//MY WHERE KIND OF CLAUSE/PREDICATE WHICH ISN'T WORKING?
NSPredicate *predicate =
[NSPredicate predicateWithFormat:#"kpiForGraphData == %#", self.kpi];
[request setPredicate:predicate];
// Create an expression to represent the function you want to apply
NSExpression *expression = [NSExpression expressionForFunction:#"max:"
arguments:[NSArray arrayWithObject:keyPathExpression]];
// Create an expression description using the minExpression and returning a date.
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
// The name is the key that will be used in the dictionary for the return value.
[expressionDescription setName:#"maxValueY"];
[expressionDescription setExpression:expression];
[expressionDescription setExpressionResultType:NSDecimalAttributeType]; // For example, NSDateAttributeType
// Set the request's properties to fetch just the property represented by the expressions.
[request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];
// Execute the fetch.
NSError *error;
id requestedValue = nil;
NSArray *objects = [context executeFetchRequest:request error:&error];
if (objects == nil) {
// Handle the error.
}
else {
if ([objects count] > 0) {
requestedValue = [[objects objectAtIndex:0] valueForKey:#"maxValueY"];
}
}
[expressionDescription release];
[request release];
return [requestedValue doubleValue];
So far I've been trying to help myself by reading docs, searching through Google and stackoverflow. Everything I seem to find either selects entities (NSPredicates) or selects values using a function. Never have I seen an example or an explanation doing what I'd like to do. I like Core Data, but right now SQL seems way more straightforward to me.

Resources