2013-11-15 4 views
0

У меня есть сложный вопрос, на мой взгляд.Редактировать объект CoreData, а затем сохранить контекст

У меня есть две сущности, одна называется InProject, которая имеет вечные атрибуты и одно отношение. отношения с другим лицом, которое называется Ins.

Я редактирую один из Ins, что связано с InProject. Я использовал InProject атрибут ID, который затем возвращает значение NSDictionary, которое имеет несколько ключевых значений, один из которых для массива Ins. Затем я нахожу Ins, мне нужно редактировать в цикле for, я их редактирую, но затем я становлюсь неуклюжим, потому что я не уверен, как сохранить contect InProject с обновленным Ins

Я хотел бы помочь код, который я сделал ниже, чтобы выяснить, как сохранить InProject после того, как я перезаписал атрибуты Ins, которые мне нужно обновить.

Это то, что мой код выглядит после недели стоит того, чтобы бороться с этой проблемой .. :(

- (void)editSelectedins:(NSString *)projIDString UpdatedNSD:(NSMutableDictionary *)updatedNSD DPC:(int)dpc{ 

     // get context 
     NSManagedObjectContext *context = [self managedObjectContext]; 

     if (context == nil) { 
      NSLog(@"Nil"); 
     } 
     else { 
      NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
      NSEntityDescription *entity = [NSEntityDescription entityForName:@"InsProject" inManagedObjectContext:context]; 
      [fetchRequest setEntity:entity]; 

      NSError *error; 
      NSMutableArray *InsProjectDictionaryArray = [[NSMutableArray alloc] init]; 
      NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error]; 

      for (InsProject *insProj in fetchedObjects) { 
       NSMutableDictionary *tempInsProjectDictionaryArray = [[ NSMutableDictionary alloc] init]; 

       [tempInsProjectDictionaryArray setObject:insProj.companyName forKey:@"CompanyName"]; 
       [tempInsProjectDictionaryArray setObject:insProj.projNo forKey:@"ProjNo"]; 
       [tempInsProjectDictionaryArray setObject:insProj.desc forKey:@"Desc"]; 
       [tempInsProjectDictionaryArray setObject:insProj.guid forKey:@"GUID"]; 
       [tempInsProjectDictionaryArray setObject:insProj.projID forKey:@"ProjID"]; 
       [tempInsProjectDictionaryArray setObject:insProj.ins forKey:@"ins"]; 

       [InsProjectDictionaryArray addObject:tempInsProjectDictionaryArray]; 
      } 

      // now that you have the InsProjects, choose the one you are curently working on in insView using the projectID 
      NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ProjID==%@",projIDString]; 
      [fetchRequest setPredicate:predicate]; 

      // new array with one value that was created using the NSPredicate ProjID 
      NSArray *tempInsProjectArray = [InsProjectDictionaryArray filteredArrayUsingPredicate:predicate]; 

      // get ins array out of the NSDictionary to edit 
      NSSet *inssForInsProject = tempInsProjectArray[0][@"ins"]; 
      NSMutableArray *tempAllinss = [[NSMutableArray alloc] init]; // this will contain everything, that means all repeated values are included 

      for (Items* currItem in [inssForInsProject allObjects]) { 
       NSArray *keys = [[[currItem entity] attributesByName] allKeys]; 
       NSDictionary *dict = [currItem dictionaryWithValuesForKeys:keys]; 
       [tempAllinss addObject:dict]; 
      } 

      NSArray *myArray = [tempAllinss copy]; 

      // get the correct items from myArray anything whos dpc matches the dpc parameter of this method 
      NSMutableArray *editedinsArray = [[NSMutableArray alloc] init]; 
      for (int i = 0; i < [myArray count]; i++) { 
       NSMutableDictionary *tempinssDictionary = [myArray objectAtIndex:i]; 

       // if you get a match put it into the new editedinsArray to be edited 
       if ([[tempinssDictionary objectForKey:@"dpc"] integerValue] == dpc) { 
        [editedinsArray addObject:tempinssDictionary]; 

       } 
      } 

      // by now you should have three things 
      // 1, access to your ins coredata object //this s wrong I actually have access to insProject 
      // 2, the values you need to be edited saved into a NSArray (editedinsArray, which will be used to check against and keep old values correct) 
      // 3, UpdatedNSD which will be used to update any values that need to be updated. 


      // go through your values and update the ins object 
      int i = 0; 
      for (ins *temp in editedinsArray) { 
       NSDictionary *currentEditedins = [editedinsArray objectAtIndex:i]; 
       i++; 

       // these values should stay the same so use currentEditedins which contains old vals 
       NSString *stringToNumberDpc = [currentEditedins valueForKey:@"dpc"]; 
       int tempDpcNum = [stringToNumberDpc integerValue]; 
       NSNumber *dpcNumber = [NSNumber numberWithInt:tempDpcNum]; 
       temp.dpc = dpcNumber; 

       NSString *totDQtyString = [currentEditedins valueForKey:@"totDQty"]; 
       if ((NSNull *)totDQtyString == [NSNull null]) { 
        temp.totDQty = @""; 
       } else { 
        temp.totDQty = totDQtyString; 
       } 

       NSString *totShipString = [currentEditedins valueForKey:@"totShip"]; 
       if ((NSNull *)totShipString == [NSNull null]) { 
        temp.totShip = @""; 
       } else { 
        temp.totShip = totShipString; 
       } 


       // values to be updated so use updatedNSD wthich was passed in as method param with the new vals 
       temp.newInsComp = [updatedNSD valueForKey:@"newInsComp"]; 
       temp.newDryComp = [updatedNSD valueForKey:@"newDryComp"]; 
       temp.updatedRow = [updatedNSD valueForKey:@"updatedRow"]; 

      } 
#warning --- I have no idea what to do here... i.e. how do I update the tempInsProjectArray.ins values I have just updated in the above for loop then save context which I hope would update insProj and the ins entities involved.   

      //save 
      [context save:&error]; 


     } 

} 

любая помощь будет массово оценили. Как вы можете видеть в нижней части кода с #warning Я объясняю, где у меня проблема. Если я запишу temp внутри цикла for, я вижу, что обновленные значения отлично имеют проблему, с которой я сталкиваюсь, - как мне затем обновлять текущие значения tempInsProjectArray.ins, которые я только что редактировал, а затем сохранить их

Надеюсь, что я предоставил вам достаточно информации, чтобы описать сложный вопрос, но я надеюсь, что кто-то там шляпа может помочь.

ответ

3

Ваш код очень нуждается в упрощении. Некоторые основные правила:

  1. Используйте имена с smallInitial и camelCase для переменных. Так что не InsProjectDictionaryArray, но insProjectDictionaryArray.
  2. То же самое относится к словарным клавишам, указывающим имена атрибутов управляемых объектов. Таким образом, projNo, а не ProjNo.
  3. Избегайте загадочных сокращений. Используйте простой и читаемый английский язык не projNo, но projectNumber. Что такое Ins? Что такое «dcp»?
  4. Не используйте множественную форму для имен сущностей. Подходящим именем для объекта является Item, а не Items
  5. Не используйте изменяемые версии словаря и массива, если это потребуются неизменные.
  6. Избегайте дублирования ваших данных, например, в [array copy].
  7. Избегайте словарей, если у вас есть граф объектов. График объекта - это то, что создает основные данные. Это делает словари со значениями и ключами ненужными.
  8. Не используйте идентификаторы. В большинстве случаев граф объектов также делает ненужным. Если вы используете идентификаторы, не используйте строки, кроме номеров, например long int или версию объекта NSNumber.
  9. При извлечении данных из постоянного хранилища основных данных не извлекайте все данные и фильтр в результат. Выбираем только нужные вам данные.

То, что вы хотите выполнить, может быть сделано в нескольких строках кода. Я попытаюсь обобщить то, что вы хотите сделать, насколько я понимаю.

Ваша модель данных выглядит следующим образом:

Project <----->> Item 

Где элементы находятся в отношениях ко многим под названием ins. Я переименую это items. Я также предполагаю, что вы будете реорганизовывать свои идентификаторы типа NSNumber.

Весь код до myArray может быть заменен следующим образом:

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:"Project"]; 
request.predicate = [NSPredicate predicateWithFormat:@"projectID = %@", projectID]; 
request.fetchLimit = 1; 
NSArray *fetchedObjects = [self.managedObjectContext 
     executeFetchRequest:request error:nil]; 
Project *project = fetchedObjects[0]; 

Теперь у вас есть все элементы, доступные только с project.items. Я понимаю, что может быть более одного элемента с таинственным атрибутом dcp типа int (т. Е. NSNumber для управляемых объектов), который равен переданному параметру dcp.

NSSet *matchingItems = [project.items filteredSetUsingPredicate: 
    [NSPredicate predicateWithFormat:@"dcp = %@", @(dcp)]]; 

Теперь это становится немного темным. Почему у вас есть тип ins в вашем цикле for, если ins действительно имеют тип Item? Затем вы вводите их в словарь ... Это должно привести к ошибке компилятора. Или у вас есть другой класс под названием ins вместо Ins ??

Во всяком случае, если вы остаетесь с деталями, то вы можете просто обновить значения с тем, что вы передаете в словаре:

for (Item *item in matchingItems) { 
    item.newInsComp = [updatedNSD valueForKey:@"newInsComp"]; 
    item.newDryComp = [updatedNSD valueForKey:@"newDryComp"]; 
    item.updatedRow = [updatedNSD valueForKey:@"updatedRow"]; 
} 

[self.managedObjectContext save:nil]; 

Готово!

BTW вы могли бы сделать его еще короче, устанавливая имя сущности запроса выборки для «Item» и заходящего следующий предикат:

[NSPredicate predicateWithFormat:@"project.projectID = %@ && dcp = %@", 
    projectID, @(dcp)]; 
+0

Мунди, большое спасибо за то, что нашли время, чтобы ответить мне. Я распечатал ваши предложения и буду следить за тем, чтобы я теперь лучше справлялся с правилами, которые вы указали. Я думаю, что, возможно, проблема усугубляет качество моего кода, поскольку я как бы уловил попытку добиться чего-то, чего я не знал о том, как добиться успеха. (если это имеет смысл) в любом случае. Я собираюсь дать вам ответ. Я отправлю обратно с моими результатами.еще раз большое спасибо за ответ и время, чтобы прочитать мой вопрос. – HurkNburkS

+0

Im в настоящее время работает через него, но я получаю сообщение об ошибке, когда поток попадает в строку, в которой вы объявляете объекты NSArray. это ошибка, которую я получаю «Завершение приложения из-за неперехваченного исключения» NSInvalidArgumentException », причина:« keypath projectID не найден в объекте » – HurkNburkS

+0

Проверьте имена атрибутов как в подклассах управляемого объекта, так и в объекте модель. Эта ошибка достаточно ясна, вы могли бы понять это. – Mundi

0

Если вы знаете свой InProject, то обновление вашего Ins, связанного с этим проектом, является вопросом редактирования значений свойств на управляемых объектах.

Почему бы не использовать предикат для получения NSManagedObject из InProject, а затем отключить связь и изменить значения?

NSManagedObjectContext *context = [self managedObjectContext]; 

if (!context) { 
    return; 
} 

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"InsProject" inManagedObjectContext:context]; 
[fetchRequest setEntity:entity]; 

    // Set the predicate on the Core Data fetch request instead 
    fetchRequest.predicate = [NSPredicate predicateWithFormat:@"ProjID==%@",projIDString]; 

NSError *error; 
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error]; 

// We now have an array that has objects matching the projectIdString 
// Might want to do some additional checks if you're only expecting zero or one objects 
InsProject *aProject = [fetchedObjects lastObject]; 

// If we have no project, no point going any further 
if (!aProject) return; 

// On this NSManagedObject is an NSSet property with all related Ins objects 
for (Ins *anIns in aProject.ins) { 

    // If our Ins item matches the passed dpc... 
    if ([ins.dpc integerValue] == dpc) { 

     // ...we have a match, edit properties 
     ins.dpc = @(dpc); 
     ins.newInsComp = [updatedNSD valueForKey:@"newInsComp"]; 
     ins.newDryComp = [updatedNSD valueForKey:@"newDryComp"]; 
     ins.updatedRow = [updatedNSD valueForKey:@"updatedRow"]; 
    } 
} 

// These are managed objects, so saving the context saves all the changes 
NSError *saveError; 
[context save:&saveError]; 
if (saveError) { 
    NSLog(@"Save error: %@", [error localizedDescription]); 
} 
+0

хорошо. Я собираюсь пройти через это с помощью тонкого зубного гребня и, надеюсь, не только получить его, но и сработает .. будет держать вас в курсе. и большое спасибо за то, что нашли время, чтобы прочитать мой вопрос и дать ответ – HurkNburkS

+0

Все еще слишком много для петель ИМО. – Mundi

+0

Я поместил ваш код в свой проект, чтобы увидеть, будут ли какие-либо предупреждения, и я получил один «Локальное объявление« проекта »скрывает переменную экземпляра», которая происходит в строке, где вы проверяете, есть ли у нас проект и возвращаем, если мы не делают. – HurkNburkS

Смежные вопросы