Уникальные атрибуты Core Data
Можно ли сделать атрибут Core Data уникальным, то есть два объекта MyEntity не могут иметь один и тот же myAttribute?
Я знаю, как принудительно применять это программно, но я надеюсь, что есть способ сделать это, используя графический редактор модели данных в xcode.
Я использую SDK для iPhone 3.1.2.
Ответы
Ответ 1
Я решил использовать метод validate<key>:error:
, чтобы проверить, есть ли уже управляемый объект с определенным значением <key>
. Ошибка возникает, если это так.
Например:
- (BOOL)validateMyAttribute:(id *)value error:(NSError **)error {
// Return NO if there is already an object with a myAtribute of value
}
Спасибо Мартину Котту за его вклад.
Ответ 2
Каждый раз, когда я создаю объект, я выполняю метод класса, который создает новое 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;
}
Ответ 3
Из 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
Здесь хорошо сказано
Захари Орр Отвечать
и он любезно также создал блогпост и образец кода.
Пример кода
Сообщение в блоге
Самая сложная часть - получить атрибуты данных модели editable.The Secret - щелкнуть левой кнопкой мыши, а затем щелкнуть правой кнопкой мыши, после того как вы нажали знак +, чтобы добавить ограничение.
![введите описание изображения здесь]()
Ответ 4
Вы можете переопределить метод 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
.
Ответ 5
Мне очень понравился подход @DoozMen!!
Я думаю, что это самый простой способ сделать то, что мне нужно было сделать.
Именно так я включил его в свой проект:
Следующие циклы кода при рисовании довольно длинного tableView, сохранение в DB объекта для каждой строки таблицы и установка различных атрибутов объекта для каждого из них, например состояния 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;
Ответ 6
Взгляните на Apple documentation для проверки на соответствие свойствам. В нем описывается, как вы можете проверить конкретную операцию вставки или обновления, имея возможность проконсультироваться со всей базой данных.