核心数据的独特属性

时间:2010-02-10 19:42:49

标签: objective-c iphone cocoa-touch xcode

是否可以使Core Data属性唯一,即没有两个MyEntity对象可以具有相同的myAttribute?

我知道如何以编程方式强制执行此操作,但我希望有一种方法可以使用xcode中的图形数据模型编辑器。

我正在使用iPhone 3.1.2 SDK。

7 个答案:

答案 0 :(得分:28)

每次我在对象上创建时,我都会执行一个类方法,只有当另一个实体不存在时才会生成新实体。

+ (TZUser *)userWithUniqueUserId:(NSString *)uniqueUserId inManagedObjectContext:(NSManagedObjectContext *)context
{
    TZUser *user = nil;
    NSFetchRequest *request = [[NSFetchRequest alloc] init];

    request.entity = [NSEntityDescription entityForName:@"TZUser" inManagedObjectContext:context];
    request.predicate = [NSPredicate predicateWithFormat:@"objectId = %@", uniqueUserId];
    NSError *executeFetchError = nil;
    user = [[context executeFetchRequest:request error:&executeFetchError] lastObject];

    if (executeFetchError) {
         NSLog(@"[%@, %@] error looking up user with id: %i with error: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), [uniqueUserId intValue], [executeFetchError localizedDescription]);
    } else if (!user) {
        user = [NSEntityDescription insertNewObjectForEntityForName:@"TZUser" 
                                             inManagedObjectContext:context];
    }

    return user;
}

答案 1 :(得分:12)

我决定使用validate<key>:error:方法检查是否已存在具有特定值<key>的托管对象。如果是这种情况,则会引发错误。

例如:

- (BOOL)validateMyAttribute:(id *)value error:(NSError **)error {
    // Return NO if there is already an object with a myAtribute of value
}

感谢Martin Cote的投入。

答案 2 :(得分:9)

从IOS 9开始,有一种处理独特约束的新方法。

您可以在数据模型中定义唯一属性。

您需要设置托管上下文合并策略“合并策略单例对象,定义在保存操作期间处理冲突的标准方法”NSErrorMergePolicy是默认值,如果存在任何合并冲突,此策略会导致保存失败。

- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (!coordinator) {
        return nil;
    }
  _managedObjectContext = [[NSManagedObjectContext alloc]    initWithConcurrencyType:NSMainQueueConcurrencyType];
  [_managedObjectContext setPersistentStoreCoordinator:coordinator];
  [_managedObjectContext setMergePolicy:NSOverwriteMergePolicy];
    return _managedObjectContext;
}

Apple Ducumentation Merge Policy

讨论了各种选项

这里很好地回答了 Zachary Orr's Answer

他还亲切地创建了一个博文和示例代码。

Sample Code

Blog Post

最具挑战性的部分是让数据模型属性可编辑。在单击+符号添加约束后,单击左键然后单击鼠标右键。

enter image description here

答案 3 :(得分:3)

您可以覆盖setMyAttribute方法(使用类别)并确保其唯一性,尽管这可能很昂贵:

- (void)setMyAttribute:(id)value
{
   NSArray *objects = [self fetchObjectsWithMyValueEqualTo:value];
   if( [objects count] > 0 )  // ... throw some exception
   [self setValue:value forKey:@"myAttribute"];
}

如果您想确保每个MyEntity实例都具有不同的myAttribute值,则可以使用objectIDNSManagedObject个对象。

答案 4 :(得分:0)

我真的很喜欢@ DoozMen的方法!! 我认为这是做我需要做的最简单的方法。

这是我将其融入我的项目的方式:

以下代码循环绘制一个相当长的tableView,为每个表行保存一个对象,并为每个表设置各种对象属性,如UISwitch状态和其他东西:如果该行的对象如果在DB内部没有某个标记,则会创建它。

NSFetchRequest *request = [[NSFetchRequest alloc] init];

request.entity = [NSEntityDescription entityForName:@"Obiettivo" inManagedObjectContext:self.managedObjectContext];
request.predicate = [NSPredicate predicateWithFormat:@"obiettivoID = %d", obTag];
NSError *executeFetchError = nil;
results = [[self.managedObjectContext executeFetchRequest:request error:&executeFetchError] lastObject];

if (executeFetchError) {
    NSLog(@"[%@, %@] error looking up for tag: %i with error: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), obTag, [executeFetchError localizedDescription]);
} else if (!results) {

    if (obbCD == nil) {
    NSEntityDescription *ent = [NSEntityDescription entityForName:@"Obiettivo" inManagedObjectContext:self.managedObjectContext];
    obbCD = [[Obiettivo alloc] initWithEntity:ent insertIntoManagedObjectContext:self.managedObjectContext];
    }

    //set the property that has to be unique..
    obbCD.obiettivoID = [NSNumber numberWithUnsignedInt:obTag];

    [self.managedObjectContext insertObject:obbCD];
    NSError *saveError = nil;
    [self.managedObjectContext save:&saveError];

    NSLog(@"added with ID: %@", obbCD.obiettivoID);
    obbCD = nil;
}

results = nil;

答案 5 :(得分:0)

查看Apple documentation以进行属性间验证。它描述了如何在能够查询整个数据库的同时验证特定的插入或更新操作。

答案 6 :(得分:0)

您只需要检查一个现有的:/

我看不到核心数据真正提供的任何帮助。约束功能以及被打破并不能真正起到作用。当然,在所有现实环境中,您只需要检查是否已经存在一个,并使用它(例如,将其作为另一项的关系字段)即可。我只是看不到其他方法。

要保存输入的任何人...

// you've download 100 new guys from the endpoint, and unwrapped the json
for guy in guys {
    // guy.id uniquely identifies
    let g = guy.id
    
    let r = NSFetchRequest<NSFetchRequestResult>(entityName: "CD_Guy")
    r.predicate = NSPredicate(format: "id == %d", g)
    
    var found: [CD_Guy] = []
    do {
        let f = try core.container.viewContext.fetch(r) as! [CD_Guy]
        if f.count > 0 { continue } // that's it. it exists already
    }
    catch {
        print("basic db error. example, you had = instead of == in the pred above")
        continue
    }
    
    CD_Guy.make(from: guy) // just populate the CD_Guy
    save here: core.saveContext()
}
or save here: core.saveContext()

core只是您的单身人士,不管您拥有什么背景和其他东西。

请注意,在该示例中,您可以在每次添加新内容时都保存saveContext,或者此后一次全部保存。

(我发现表格/集合绘制得如此之快,与CD结合使用,真的无关紧要。)

(不要忘记.privateQueueConcurrencyType)

请注意,此示例不会显示,基本上,您是创建实体并在另一个上下文中书写的,并且您必须使用.privateQueueConcurrencyType,而不能使用与您的表格/集合.. .viewContext。

let pmoc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
pmoc.parent = core.container.viewContext
do { try pmoc.save() } catch { fatalError("doh \(error)")}