2010-02-10 4 views
35

Можно ли сделать атрибут Core Data уникальным, то есть нет двух объектов MyEntity, имеющих один и тот же атрибут myAttribute?Основные атрибуты данных ядра

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

Я пользуюсь iPhone 3.1.2 SDK.

+15

Почему этот вопрос закрыт? Приведенная причина заключалась в том, что «Вопросы, требующие кода, должны демонстрировать минимальное понимание решаемой проблемы», но я вообще не запрашивал код - я хотел знать, удалось ли это сделать в графическом редакторе в Xcode. (Ответ фактически оказался «нет, но вот некоторые обходные пути».) – robinjam

ответ

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 для его ввода.

+1

При запросе убедитесь, что вы используете 'self.managedObjectContext', чтобы убедиться, что вы проверяете существование дубликата в правильном' managedObjectContext'. В противном случае Save As (т.е. переход на новый URL-адрес) завершится с ошибкой. –

+1

Выполнение выборки изменит граф объектов в контексте управляемого объекта - это не то, что вы хотите сделать внутри метода проверки! – quellish

+0

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

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 значение, то может использовать objectID объектов NSManagedObject.

+0

Спасибо за быстрый ответ! «Вы можете переопределить setMyAttribute» Это то, что я делаю в данный момент. К счастью, набор данных достаточно мал, чтобы получить список всех объектов не слишком дорого, хотя я надеялся, что было бы более элегантное решение. «Если вы хотите убедиться, что каждый экземпляр MyEntity имеет отличное значение myAttribute ...» Это именно то, что я хочу сделать, хотя я изо всех сил пытаюсь понять, как можно использовать идентификатор объекта для этой цели , Можно ли каким-либо образом присвоить свой собственный идентификатор каждому объекту? – robinjam

+1

@robinjam, я больше говорил о том, что вы можете подключить значение objectID где-нибудь в «myAttribute», чтобы гарантировать, что все значения уникальны. –

+0

О, я понимаю, что вы сейчас имеете в виду. Однако данный атрибут является фактически предоставленным пользователем именем, поэтому это не было бы идеальным для моей цели. Причина, по которой я хочу сохранить их уникальными, заключается в том, что у пользователя не будет возможности разделить два объекта с одним и тем же именем. См. Мой ответ на решение, которое я решил в конце. Спасибо за ваш вклад! – robinjam

28

Каждый раз, когда я создаю объект, я выполняю метод класса, который создает новое Entity только тогда, когда другого не существует.

+ (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; 
} 
+0

Это самый простой и ясный взгляд на этот дизайн, который я видел. Благодаря! – radven

+0

Это действительно фантастическое решение. Увидев это, это кажется таким очевидным. Теперь я все еще новичок в этом, поэтому, возможно, есть некоторые недостатки в этом, но отлично работает для моего приложения, насколько я могу судить. Спасибо, что поделился! – daveomcd

+1

Проблема с этим подходом заключается в том, что вы берете IO. Как этого избежать? –

0

Мне очень понравился подход @DoozMen !! Я думаю, что это самый простой способ сделать то, что мне нужно.

Это путь я вставил его в свой проект:

Следующие циклы кода при рисовании довольно долго Tableview, сохранение в БД объект для каждой строки таблицы, а также создание различных атрибутов объекта для каждого из них, как UISwitch состояния и другие вещи: если объект для строки с определенным тегом отсутствует внутри БД, он создает его.

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; 
0

Посмотрите на Apple, documentation для проверки между собственности. В нем описывается, как вы можете проверить конкретную операцию вставки или обновления, имея возможность проконсультироваться со всей базой данных.

+0

Ссылка не работает – webo80

+1

Обновлено сейчас. – Litherum

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

и он любезно также создал BlogPost и примеры кода.

Sample Code

Blog Post

Самая сложная часть, чтобы получить модель данных атрибутов editable.The Секрет щелкните левой кнопкой мыши, а затем щелкните правой кнопкой мыши, после того, как вы нажали на знак +, чтобы добавить ограничение.

enter image description here

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