3 votes

Les données de base sont extraites en fonction des propriétés des relations "ordonnées".

Mon application a une fonctionnalité de type dossier intelligent : un prédicat est configuré avec un NSPredicateEditor et utilisé pour remplir le dossier avec une requête de récupération.

L'entité utilisée dans la recherche a une relation de type "to-many". La relation est ordonnée, en ce sens qu'un index est stocké dans l'entité de destination à des fins de tri.

Mon problème est que je voudrais intégrer une règle basée sur les dernières valeurs de la relation ordonnée, mais je n'arrive pas à trouver comment construire un prédicat pour le faire, car la relation n'est pas un tableau. Les données de base ne connaissent pas l'ordre.

J'ai une propriété en lecture seule sur la classe qui renvoie les articles commandés, mais cela ne semble pas aider la requête de récupération car la propriété n'est pas disponible dans le magasin de données principal.

La seule option à laquelle je pense est de dé-normaliser et de stocker les derniers éléments de la relation ordonnée dans une propriété séparée. Est-ce la seule solution ?

2voto

Daniel Thorpe Points 2413

Eh bien, en supposant que j'ai bien compris le problème, je procéderais comme suit. Disons que vous avez deux entités, TopEntity a une propriété (NSString *)name et une relation to-many avec MyEntity qui a une propriété (NSString *)data et une propriété (NSInteger)order.

Disons que vous voulez les objets TopEntity qui correspondent à une chaîne de caractères donnée, et dont les commandes MyEntity satisfont à une certaine condition, alors vous pouvez le faire avec deux prédicats et une NSFetchRequest comme suit....

NSManagedObjectContext *context = [self managedObjectContext];

// Create some top level entities
TopEntity *aTop = [TopEntity insertInManagedObjectContext:context];
aTop.name = @"This is Your Name";
TopEntity *bTop = [TopEntity insertInManagedObjectContext:context];
bTop.name = @"This aint a Name";    
TopEntity *cTop = [TopEntity insertInManagedObjectContext:context];
cTop.name = @"This is My Name";    

// Add some data
NSInteger i, len = 30;
for(i=0; i<len; i++) {
    // Create a new object
    MyEntity *entity = [MyEntity insertInManagedObjectContext:context];
    entity.orderValue = i;
    entity.data = [NSString stringWithFormat:@"This is some data: %d", i];
    if(i < 10) {
        [aTop addObjectsObject:entity];
        [entity addTopObject:aTop];
    } else if (i < 20) {
        [bTop addObjectsObject:entity];
        [entity addTopObject:bTop];            
    } else {
        [cTop addObjectsObject:entity];
        [entity addTopObject:cTop];                        
    }
}

// Save the context
NSError *error = nil;
[context save:&error];

// A predicate to match against the top objects
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name BEGINSWITH %@", @"This is"];
// A predicate to match against the to-many objects
NSPredicate *secondPredicate = [NSPredicate predicateWithFormat:@"ANY objects.order < %d", 5];
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
[fetch setEntity:[NSEntityDescription entityForName:@"TopEntity" inManagedObjectContext:context]];
[fetch setPredicate:predicate];
NSArray *result = [[context executeFetchRequest:fetch error:&error] filteredArrayUsingPredicate:secondPredicate];

for(TopEntity *entity in result) {
    NSLog(@"entity name: %@", entity.name);         
}

Donc, essentiellement, vous pouvez simplement envelopper les résultats de votre requête de récupération avec un autre prédicat et utiliser le mot-clé ANY.

Je n'ai aucune idée de l'efficacité de cette méthode, mais elle fonctionne dans ce cas. L'exécution de la commande ci-dessus produira "This is Your Name", c'est-à-dire qu'elle correspond à la première TopEntity.

1voto

Joshua Nozzi Points 38718

Je ne pense pas qu'il y ait un moyen de limiter à n dans un prédicat, uniquement au niveau de la requête de récupération.

En plus de référencer les n derniers éléments dans une relation comme vous l'avez mentionné, vous pourriez essayer un attribut booléen "lastN" et les activer/désactiver lorsque vous modifiez l'ordre de la liste (par exemple, lors d'un tri initié par l'utilisateur ou d'une réorganisation par glisser-déposer).

Vous pouvez également créer une requête de récupération distincte pour chaque objet recherché, qui trie par votre clé de tri, par ordre décroissant, et qui est limitée (via -setFetchLimit : ) à n les résultats.

Le suivi de ces données en tant que relation ou attribut est quelque peu "désordonné", tandis que la limite d'extraction est plus coûteuse (en raison des multiples allers-retours). Si votre réorganisation est effectuée par des actions uniques de l'utilisateur, il peut être plus performant d'utiliser l'approche par relation ou par attribut puisque le travail est amorti plutôt que d'être effectué en une seule fois dans une série d'extractions. Je n'ai pas trouvé de meilleure méthode moi-même et je suivrai cette affaire de près :-)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X