コアデータ属性を一意にすることは可能ですか?つまり、2つのMyEntityオブジェクトが同じmyAttributeを持つことはできませんか?
私はこれをプログラムで強制する方法を知っていますが、xcodeのグラフィカルデータモデルエディターを使用してそれを実行する方法があることを望んでいます。
IPhone 3.1.2 SDKを使用しています。
validate<key>:error:
メソッドを使用して、特定の値が<key>
の管理対象オブジェクトがすでに存在するかどうかを確認することにしました。この場合、エラーが発生します。
例えば:
-(BOOL)validateMyAttribute:(id *)value error:(NSError **)error { // myAtributeの値が }のオブジェクトがすでにある場合は、NOを返します
Martin Cote氏の情報提供に感謝します。
オブジェクトを作成するたびに、別のエンティティが存在しない場合にのみ新しいエンティティを作成するクラスメソッドを実行します。
+ (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;
}
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
また、ブログポストとサンプルコードも作成してくださいました。
最も難しい部分は、データのモデル属性を編集可能にすることです。秘密は、+記号をクリックして制約を追加した後、左クリックしてから右クリックすることです。
(カテゴリを使用して)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
を使用できます。
これに役立つコアデータが実際に提供するものは何もありません。制約機能は壊れているだけでなく、実際には機能しません。もちろん、現実世界のすべての状況で、単に存在するかどうかを確認し、存在する場合はそれを使用する必要があります(たとえば、もちろん、別のアイテムの関係フィールドとして)。他のアプローチが見当たらないだけです。
入力中のユーザーを保存するには...
// 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と組み合わせると、テーブルやコレクションの描画が非常に速くなるので、実際には無関係です。)
この例に注意してくださいDOES NOT show基本的に、エンティティを作成して別のコンテキストに書き込みます。.privateQueueConcurrencyType
を使用する必要があります。テーブルと同じコンテキストを使用することはできません/コレクション.. .viewContext。
let pmoc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
pmoc.parent = core.container.viewContext
do { try pmoc.save() } catch { fatalError("doh \(error)")}
プロパティ間の検証については、Apple documentation をご覧ください。データベース全体を調べながら、特定の挿入または更新操作を検証する方法について説明しています。
@DoozMenアプローチが本当に好きでした!!それは私がする必要があることをする最も簡単な方法だと思います。
これは私がそれを自分のプロジェクトに組み込んだ方法です:
次のコードは、かなり長いtableViewを描画し、各テーブル行のオブジェクトをDBに保存し、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;