基于属性评估创建CoreData实体



假设我有一个具有标准属性的实体MeetingNote,加上与另一个实体Tagone to many关系。

MeetingNote实例中,我想创建另一个名为Task的实体的实例,但前提是meetingNote.tag.name == 'task'TRUE

你认为对TaskMeetingNote之间的关系建模的正确方法是什么?或者应该有一个关系,而我应该使用一个带有适当谓词的提取属性?

首先,核心数据的真正目的不是持久性,而是创建模型-视图-控制器设计应用程序的模型层。这意味着核心数据实际上首先是模型/模拟API,其次是持久性API。因此,核心数据数据模型应该准确地表示真实世界对象、条件或事件的属性以及它们之间的关系。

因此,当你着手构建数据模型时,你应该忘记UI、数据源或任何其他实现细节,只需尝试创建一个反映应用程序处理的真实世界对象、条件或事件的模型。

其次,虽然数据模型处理实体如何相关,但它不处理实体为什么相关的逻辑。该逻辑属于代码中,通常位于实体的自定义NSManagedObject子类中。在这种情况下,实体关系的howMeetingNote实体与TaskTags都相关。的原因是,只有当MeetingNote对象与名为taskTag对象有关系时,任何特定的MeetingNote对象和任何Task对象之间才应该有关系。

所以,你的基本数据模型应该是这样的:

MeetingNote{
  title:string
  date:date
  tags<<-->>Tag.meetingNotes
  tasks<-->>Task.meetingNote
}
Task{
  name:string
  meetingNote<<-->MeetingNote.tasks
}
Tag{
  name:string
  meetingNotes<<-->>MeetingNote.tags
}

现在的问题是,为什么的自定义逻辑应该放在哪里。逻辑上最简单的方法是为MeetingNote.tags属性创建一个自定义访问器,该访问器检查添加或删除到MeetingNote instance的标记的名称是否等于task,如果是,则从实例的MeetingNote.tasks关系中添加或删除Task对象。

然而,这会带来明显的性能损失,即必须检查添加或删除的每个标记。一个更好的解决方案是将自定义添加到只有当MeetingNote.tags.name' contains a value of任务的确切条件为"时才调用的一个点。

假设您有以下限制:

  1. 一个MeetingNote对象如果没有Tag object with name=="task",就不能具有相关的Task对象
  2. 如果MeetingNote对象确实具有Tag object with name=="task",则它必须至少具有一个相关的Task对象
  3. 如果MeetingNote对象失去了与Tag object with name=="task"的关系,那么它将失去所有任务

在这一点上很明显,`Tag object with name="task"是一个特殊的对象,其行为与其他标记不同。这证明并要求它有自己的实体和子类,因此我们将添加到数据模型中:

TaskTag:Tag{
}

由于TaskTag实体继承自Tag实体,因此它可以在Tag.meetingNotes关系中自动继承,因此从任何MeetinNote对象的角度来看,它将表现为Tag对象。

然后在TaskTagNSManagedObject子类中,我们将添加以下代码:

-(NSString *) name {
  // the name of a TaskTag is always "task" 
  //  you should set the defalut value in the data model to "task" as well.
  return @"task"; 
}
-(void) setName:(NSString *)name{
  return; // the name can never be changed
}
- (void)addMeetingNotesObject:(MeetingNote *)value {    
  NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
  [self willChangeValueForKey:@"meetingNotes" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
  [[self primitiveValueForKey:@"meetingNotes"] addObject:value];
  // If the meeting object does not an existing task, add one
  if ([value.tasks count]==0 ) {
    Task *t=[NSEntityDescription insertNewObjectForEntityForName:@"Task" inManagedObjectContext:self.managedObjectContext];
    t.meetingNote=value;
  }
  [self didChangeValueForKey:@"meetingNotes" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changedObjects];
  [changedObjects release];
}
- (void)removeMeetingNotesObject:(MeetingNote *)value {
  NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
  [self willChangeValueForKey:@"meetingNotes" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
  [[self primitiveValueForKey:@"meetingNotes"] removeObject:value];
  // A MeetingNote object cannot have any task without a taskTag so remove all task objects
  if ([value.tasks count]!=0 ) {
    [value removeTasks:value.tasks]; // removes all tasks from meeting notes
  }
  [self didChangeValueForKey:@"meetingNotes" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changedObjects];
  [changedObjects release];
}
- (void)addMeetingNotes:(NSSet *)value {    
  [self willChangeValueForKey:@"meetingNotes" withSetMutation:NSKeyValueUnionSetMutation usingObjects:value];
  [[self primitiveValueForKey:@"meetingNotes"] unionSet:value];
  Task *newTask;
  // same as addMeetingNotesObject:
  for (MeetingNote *meetNote in value) {
    if ([meetNote.tasks count]==0 ) {
      newTask=[NSEntityDescription insertNewObjectForEntityForName:@"Task" inManagedObjectContext:self.managedObjectContext];
      newTask.meetingNote=value;
    }
  }
  [self didChangeValueForKey:@"meetingNotes" withSetMutation:NSKeyValueUnionSetMutation usingObjects:value];
}
- (void)removeMeetingNotes:(NSSet *)value {
  [self willChangeValueForKey:@"meetingNotes" withSetMutation:NSKeyValueMinusSetMutation usingObjects:value];
  [[self primitiveValueForKey:@"meetingNotes"] minusSet:value];
  //removeMeetingNotesObject:
  for (MeetingNote *meetNote in value) {
    [meetNote removeTasks:meetNote.tasks]; 
  }
  [self didChangeValueForKey:@"meetingNotes" withSetMutation:NSKeyValueMinusSetMutation usingObjects:value];
}
// Note: This code is not compiled and my contain errors.

此代码将自动强制执行上面的约束,而无需执行任何其他操作。您还可以自定义Task子类,以便根据与其相关的MeetingNote对象的某些属性自动设置其名称。

现在,您已经在数据模型中拥有了why的所有逻辑,并且您的约束将自动强制执行。这可能不是你需要的确切解决方案,但你已经明白了。

有趣的问题。我在这里的经验有限,但我忍不住尝试了一个答案:

如果您期望对MeetingNote进行大量编辑,这些编辑需要立即反映在Task中,反之亦然,则关系会自动使加载的对象相互更新。(我基于Richard Stahl在这里的帖子:提取的属性与关系。)否则,提取的属性可能会在错误方面更有效。

但你为什么要把MeetingNote和Tag之间的关系当作一对多呢?这意味着一个标签只能有一个MeetingNote。正确的因此,每当meetingNote被标记为"task"时,都必须创建一个单独的标记。多对多不是更好吗?

然后,如果按照关系路线,你会在MeetingNote和Task之间建立一对一的关系。即使您希望多个meetingNotes共享一个任务,由于该任务必须直接从meetingNote派生,因此您无论如何都要创建单独的任务。由于您要为每个标记为meetingNote的任务创建一个任务实例,因此这些任务不应该有多个meetingNote关系,因为这会造成令人困惑的重复。

最新更新