objective-c 核心数据的独特属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2239797/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Core Data unique attributes
提问by robinjam
Is it possible to make a Core Data attribute unique, i.e. no two MyEntity objects can have the same myAttribute?
是否可以使核心数据属性唯一,即没有两个 MyEntity 对象可以具有相同的 myAttribute?
I know how to enforce this programatically, but I'm hoping there's a way to do it using the graphical Data Model editor in xcode.
我知道如何以编程方式执行此操作,但我希望有一种方法可以使用 xcode 中的图形数据模型编辑器来执行此操作。
I'm using the iPhone 3.1.2 SDK.
我正在使用 iPhone 3.1.2 SDK。
采纳答案by robinjam
I've decided to use the validate<key>:error:method to check if there is already a Managed Object with the specific value of <key>. An error is raised if this is the case.
我决定使用该validate<key>:error:方法来检查是否已经有一个特定值为<key>. 如果是这种情况,则会引发错误。
For example:
例如:
- (BOOL)validateMyAttribute:(id *)value error:(NSError **)error {
// Return NO if there is already an object with a myAtribute of value
}
Thanks to Martin Cote for his input.
感谢 Martin Cote 的投入。
回答by doozMen
Every time i create on object I perform a class method that makes a new Entity only when another one does not exist.
每次我在对象上创建时,我都会执行一个类方法,该方法仅在另一个实体不存在时创建一个新实体。
+ (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;
}
回答by Ryan Heitner
From IOS 9 there is a new way to handle unique constraints.
从 IOS 9 开始,有一种处理唯一约束的新方法。
You define the unique attributes in the data model.
您可以在数据模型中定义唯一属性。
You need to set a managed context merge policy "Merge policy singleton objects that define standard ways to handle conflicts during a save operation" NSErrorMergePolicy is the default,This policy causes a save to fail if there are any merge conflicts.
您需要设置托管上下文合并策略“合并策略单例对象,定义在保存操作期间处理冲突的标准方法” 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;
}
The various option are discussed at Apple Ducumentation Merge Policy
Apple Ducumentation Merge Policy中讨论了各种选项
It is answered nicely here Zachary Orr's Answer
Zachary Orr 的回答在这里得到了很好 的回答
and he has kindly also created a blogpost and sample code.
他还友好地创建了一篇博文和示例代码。
The most challenging part is to get the data Model attributes editable.The Secret is to left click and then right click, after you have clicked the + sign to add a constraint.
最具挑战性的部分是让数据模型属性可编辑。秘诀是左键单击然后右键单击,在您单击 + 号后添加约束。
回答by Martin Cote
You could override the setMyAttributemethod (using categories) and ensure uniqueness right there, although this may be expensive:
您可以覆盖该setMyAttribute方法(使用类别)并确保那里的唯一性,尽管这可能很昂贵:
- (void)setMyAttribute:(id)value
{
NSArray *objects = [self fetchObjectsWithMyValueEqualTo:value];
if( [objects count] > 0 ) // ... throw some exception
[self setValue:value forKey:@"myAttribute"];
}
If you want to make sure that every MyEntityinstance has a distinct myAttributevalue, you can use the objectIDof the NSManagedObjectobjects for that matter.
如果你想确保每个MyEntity实例有一个不同的myAttribute值,可以使用objectID的的NSManagedObject对象为这一问题。
回答by Paolo83
I really liked @DoozMen approach!! I think it's the easiest way to do what i needed to do.
我真的很喜欢@DoozMen 方法!!我认为这是做我需要做的事情的最简单方法。
This is the way i fitted it into my project:
这是我将它安装到我的项目中的方式:
The following code cycles while drawing a quite long tableView, saving to DB an object for each table row, and setting various object attributes for each one, like UISwitchstates and other things: if the object for the row with a certain tag is not present inside the DB, it creates it.
下面的代码在绘制一个很长的 tableView 时循环,为每个 table 行保存一个对象到 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;
回答by Litherum
Take a look at the Apple documentationfor inter-property validation. It describes how you can validate a particular insert or update operation while being able to consult the entire database.
查看 Apple文档以进行属性间验证。它描述了如何在能够查询整个数据库的同时验证特定的插入或更新操作。
回答by Fattie
You just have to check for an existing one :/
你只需要检查一个现有的:/
I just see nothing that core data really offers that helps with this. The constraints feature, as well as being broken, doesn't really do the job. In all real-world circumstances you simply need to, of course, check if one is there already and if so use that one (say, as the relation field of another item, of course). I just can't see any other approach.
我只是看不到核心数据真正提供的任何帮助。约束功能以及被破坏的功能并不能真正发挥作用。当然,在所有现实世界的情况下,您只需要检查一个是否已经存在,如果已经存在,则使用那个(当然,例如,作为另一个项目的关系字段)。我只是看不到任何其他方法。
To save anyone typing...
为了保存任何人打字...
// 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()
coreis just your singleton, whatever holding your context and other stuff.
core只是你的单身人士,不管你的上下文和其他东西。
Note that in the example you can saveContext either each time there's a new one added, or, all at once afterwards.
请注意,在示例中,您可以在每次添加新内容时保存上下文,也可以在之后一次性保存。
(I find tables/collections draw so fast, in conjunction with CD, it's really irrelevant.)
(我发现表格/收藏画得如此之快,结合 CD,这真的无关紧要。)
(Don't forget about .privateQueueConcurrencyType )
(不要忘记 .privateQueueConcurrencyType )
Do note that this example DOES NOT showthat you, basically, create the entity and write on another context, and you must use .privateQueueConcurrencyTypeYou can't use the same context as your tables/collections .. the .viewContext .
请注意,此示例并未显示您基本上创建实体并在另一个上下文中写入,并且您必须使用.privateQueueConcurrencyTypeYou can't use the same context as your tables/collections .. the .viewContext 。
let pmoc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
pmoc.parent = core.container.viewContext
do { try pmoc.save() } catch { fatalError("doh \(error)")}


