web-dev-qa-db-fra.com

Attributs uniques de données de base

Est-il possible de rendre un attribut Core Data unique, c'est-à-dire qu'aucun objet MyEntity ne peut avoir le même attribut myAttribute?

Je sais comment appliquer cela par programmation, mais j'espère qu'il sera possible de le faire en utilisant l'éditeur graphique de modèle de données dans xcode.

J'utilise le SDK iPhone 3.1.2.

35
robinjam

J'ai décidé d'utiliser la méthode validate<key>:error: pour vérifier s'il existe déjà un objet géré avec la valeur spécifique <key>. Si c'est le cas, une erreur est générée.

Par exemple:

- (BOOL) validateMyAttribute: (id *) erreur de valeur: (NSError **) error {
 // Renvoie NO s'il existe déjà un objet avec un myAtribute de valeur 
}

Merci à Martin Côté pour sa contribution.

12
robinjam

Chaque fois que je crée sur un objet, j'exécute une méthode de classe qui crée une nouvelle entité uniquement lorsqu'il en existe une autre.

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

De IOS 9, il existe un nouveau moyen de gérer des contraintes uniques.

Vous définissez les attributs uniques dans le modèle de données.

Vous devez définir une stratégie de fusion de contexte géré "Objets singleton de stratégie de fusion définissant des méthodes standard de gestion des conflits lors d'une opération de sauvegarde". NSErrorMergePolicy est la stratégie par défaut. Cette stratégie entraîne l'échec de l'enregistrement si des conflits de fusion se produisent.

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

Les différentes options sont discutées à Politique de fusion Apple Ducumentation

La réponse est ici Réponse de Zachary Orr

et il a gentiment également créé un article de blog et un exemple de code.

Exemple de code

Article de blog

La partie la plus difficile consiste à obtenir les attributs de modèle de données modifiables. Le secret consiste à cliquer avec le bouton gauche de la souris, puis à faire un clic droit, après avoir cliqué sur le signe + pour ajouter une contrainte.

 enter image description here

9
Ryan Heitner

Vous pouvez remplacer la méthode setMyAttribute (à l'aide de catégories) et en garantir l'unicité, même si cela peut coûter cher:

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

Si vous voulez vous assurer que chaque instance MyEntity a une valeur myAttribute distincte, vous pouvez utiliser la objectID des objets NSManagedObject pour cette affaire.

3
Martin Cote

Consultez la documentation Apple pour la validation inter-propriété. Il décrit comment valider une opération d’insertion ou de mise à jour particulière tout en permettant de consulter la base de données entière.

0
Litherum

J'ai vraiment aimé l'approche @DoozMen !! Je pense que c'est le moyen le plus simple de faire ce que je devais faire.

Voici comment je l'ai intégré à mon projet:

Le code suivant se répète tout en dessinant une tableView assez longue, en enregistrant dans la base de données un objet pour chaque ligne du tableau et en définissant divers attributs d'objet pour chaque élément, tels que les états UISwitch et autres: si l'objet de la ligne avec une balise donnée n'est pas présent à l'intérieur de la base de données, il le crée.

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
Paolo83