编辑CoreData对象,然后保存上下文

时间:2013-11-15 22:07:42

标签: ios core-data nsdictionary nsmutabledictionary nsset

我认为我有一个难题。

我有两个实体,一个叫InProject,有几个属性和一个关系。 这种关系与另一个名为Ins的实体有关。

我正在编辑与Ins相关的InProject之一。我使用InProject attribure ID然后返回一个NSDictionary值,该值具有几个键值,其中一个键值为Ins数组。然后我找到了我需要在for循环中编辑的Ins我编辑它们,但随后我变得不安,因为我不确定如何使用*更新Ins

来保存InProject的内容

我希望在下面的代码中提供一些帮助,以便在我覆盖我需要更新的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的代码底部看到我解释我遇到问题的地方。如果我在for循环中记录temp我完全看到更新的值我遇到的问题是如何更新我刚刚编辑的当前tempInsProjectArray.ins值?然后保存当然。

我希望我已经为您提供了足够的信息,但是我希望有人可以提供帮助。

2 个答案:

答案 0 :(得分:3)

您的代码非常需要简化。一些基本规则:

  1. 将名称与smallInitial和camelCase一起用于变量。所以不是InsProjectDictionaryArray而是insProjectDictionaryArray
  2. 这同样适用于指示管理对象的属性名称的字典键。所以projNo,而不是ProjNo
  3. 避免使用含义模糊的缩写词。使用简单易读的英语不是projNo,而是projectNumber。什么是Ins?什么是“dcp”?
  4. 不要将复数形式用于实体名称。项目的合适名称为Item,而非Items
  5. 当不可变的版本可以使用时,不要使用字典和数组的可变版本。
  6. 避免重复数据,例如[array copy]
  7. 拥有对象图时避免使用词典。对象图是核心数据创建的。它不需要使用值和键来呈现字典。
  8. 不要使用ID。在大多数情况下,对象图也会使这些不必要。如果您使用ID,请不要使用字符串,而是使用数字(例如long int)或对象版本NSNumber
  9. 从Core Data持久性存储中获取数据时,不要获取所有数据并过滤结果。只获取您需要的数据。
  10. 您想要完成的工作肯定可以通过几行代码完成。根据我的理解,我会尝试总结你想做的事情。

    您的数据模型如下所示:

    Project <----->> Item
    

    项目处于称为ins的多对多关系中。我将重命名此items。我还假设您将ID重构为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实际上是ins类型,为什么你的for循环中有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)];
    

答案 1 :(得分:0)

如果您了解自己的InProject,那么更新与该项目相关的Ins就是编辑托管对象的属性值。

为什么不使用谓词来获取InProject的NSManagedObject,然后从中拉出关系并编辑值?

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]);
}