创建新的核心数据对象如果它不存在,或者如果核心数据存在则获取现有对象

时间:2013-11-19 12:15:46

标签: ios uitableview core-data nspredicate nsfetchrequest

我一直在研究这个问题很多天,我需要帮助,因为我不知道该怎么办。我所面临的问题(当你阅读这个问题时会变得更清楚)是我不确定如果现有的NSManagedObject在创建新的NSManagedObject时已经存在。

让我们退一步看看模型,应用程序的前提很简单;允许用户创建具有名称,金额,场合和日期的“交易” - 在创建新交易时,应允许用户选择现有名称。数据模型:

  • 具有wasGiven属性的交易实体
  • 具有名称属性的人员实体
  • 具有标题属性
  • 的场合实体
  • 具有金额属性的项目实体

事务与Person实体(whoBy),Occasion Entity(场合)的链接以及Item Entity(itemType)的链接有关系。

App是一个简单的2 Tabb-ed表视图控制器 - 第一个选项卡包含所有信息,按日期划分。第二个选项卡仅包含“名称”信息。有一个加号按钮,当用户按下它时,它们会显示一个模态视图,以添加名称,场合,数量和日期。他们按保存并将其保存到核心数据数据库。

问题 使用新名称创建新事务可以完美地创建。 使用现有名称创建新事务(用户手动键入相同的名称)会在第一个选项卡中创建一个新对象作为单独的条目(正确),但在名称选项卡中,它会为该人员创建一个重复的名称。单击任一重复名称时,它会显示两个事务。这里的问题是它看起来像每次创建一个新的Person对象而不是引用。

代码

我已经通过MULTIPLE迭代尝试使其工作,这是最新的代码,使用NSManagedObject的子类。

从App Delegate获取managedObjectContext。

名称,事件,金额和日期存储在自己的文本字段中。

AddEntry.m - 保存方法

- (IBAction)save:(id)sender
{
    NSManagedObjectContext *context = [self managedObjectContext];
    Transaction *transaction = [NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:context];
    Item *itemType = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext:context];
    Person *p = (Person *)[Person personWithName:self.nameTextField.text inManagedObjectContext:context];
    Occasion *o = (Occasion *)[Occasion occasionWithTitle:self.occasionTextField.text andEventDate:self.dateTextField.text inManagedObjectContext:context];

    transaction.whoBy = p;
    occasion.title = self.occasionTextField.text;
    transaction.occasion = o; 


    itemType.amount = self.itemTextField.text;
    transaction.item = itemType;
    transaction.wasReceived = @(self.isReceivedSegment.selectedSegmentIndex == 0);
    NSError *error = nil;
    if (![context save:&error])
    {
        NSLog(@"Can't save! %@ %@", error, [error localizedDescription]);
    }
    [self dismissViewControllerAnimated:YES completion:nil];
}

这当然调用Person NSManagedObject子类,这里是我经历了几次迭代的地方。

Person NSManagedObject Subclass - Iteration 1 - Predicates

+ (Occasion *)eventWithName:(NSString *)title andEventDate:(NSString *)date inManagedObjectContext:(NSManagedObjectContext *)context;
{
    Occasion *occasion = nil; 
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Occasion"];
    request.predicate = [NSPredicate predicateWithFormat:@"title = %@", title];
    NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"title" ascending:YES];
    request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];

    NSError *error = nil;
    NSArray *occasions = [context executeFetchRequest:request error:&error];

    if (!occasions)
    {
        // Handle Error
    }
    else if (![occasions count])
    {
        occasion = [NSEntityDescription insertNewObjectForEntityForName:@"Occasion" inManagedObjectContext:context];
        occasion.title = title;
    }
    else
    {
        occasion = [occasions lastObject];   
    }
    occasion.dateOfEvent = date; 
    return occasion; 
}

问题 这有点奏效。我放置了一个断点,返回的“person”在这里返回并且添加条目中的save方法如果对象已经存在则是相同的,如果是新对象则是new,但是当它到达第二个选项卡时,它仍然是为同一个人添加第二个条目。

迭代2 - objectID

尝试获取对象ID时,我在第二个选项卡中得到了重复条目的相同结果:

+ (Person *)personWithName:(NSString *)name inManagedObjectContext:(NSManagedObjectContext *)context;
{
    Person *person;

    NSManagedObjectID *personID = person.objectID;

    if (!personID)
    {
        person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];
        person.name = name;
        return person;
    }
    else
    {
        return person;
    }
}

如果重要,第二个标签的fetchRequest如下:

- (NSFetchedResultsController *)fetchedResultsController
{
    if (_fetchedResultsController != nil)
    {
        return _fetchedResultsController;
    }
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Occasion" inManagedObjectContext:managedObjectContext];
    fetchRequest.entity = entity;
    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:NO];
    fetchRequest.sortDescriptors = [NSArray arrayWithObject:sort];
    fetchRequest.fetchBatchSize = 20;
     NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    self.fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;
    return _fetchedResultsController;
}

修改 我想知道我在第二个标签fetchRequest中没有谓词这一事实意味着它说明了所有对象..

当然,我将来会证明这一点,因为在第一个标签中,当我点击一个单元格时,我想让“交易”通过,以便我可以编辑该字段。

这让我发疯,并且真的阻止了我的应用程序的进展,所以这里的任何帮助都会受到大力赞赏!

编辑:包含数据模型

enter image description here

2 个答案:

答案 0 :(得分:1)

好的,这就是发生的事情......你添加第一个交易,一个名字U提供杰克,然后你添加第二个交易(T进一步在文本中)并添加名称约翰,在你添加名字杰克的第三个T并添加另一个名叫约翰。如果你看看数据库中的表,你会看到Transitions表有4个条目因为你添加了4个转换,但是Persons只有两个。它有两个原因你在Persons输入上添加了一个过滤器,因此它不能包含两个相同的名称。你犯的错误是你试图从Transition表中获取所有条目。当然U得到4个名字(2个Johns和2个Jacks)导致Transition表中有R 4个条目,每个条目都与Person记录相关联。如果你想要获取所有人,你不应该从Transition表中获取它,你应该从Persons表中执行它或者你应该添加[r setReturnsDistinctResults:YES];如果U R从Transition表中获取,你的获取请求...我认为有一种方法可以设置不同的属性,但我不知道语法。所以问题实际上在你想做什么,你想要呈现你的数据库中的所有人,或者你想在你的过渡上呈现名字,这意味着同一个人可以做出不同的过渡。见......

答案 1 :(得分:0)

我认为你有Transaction<< -Person所以在事务管理对象中,由于这种关系,你有一组人。当您将相同的人添加到事务时,它会创建一个新的托管对象并将其添加到集合中,如果您按名称获取,您将拥有多个具有相同名称的事务记录,但这并不意味着您有多个人。直接在Persons表上进行获取,您将看到值是不同的......

我建议您安装类似Firefox的东西并使用sqlLiteManager在数据库本身中占据一席之地......