2012-11-07 5 views
5

Für das Leben von mir kann ich nicht scheinen, dass dies funktioniert.Wie konstruieren Sie das Prädikat für NSFetchRequest setHavingPredicate :?

Angenommen, unsere Entität ist ein verwaltetes Objekt mit einem Statusfeld und einem Auftragsfeld.

Wie würde ich alle geordertenEinträge mit mehr als einer Bestellung, die die gleichen sind, gehen?

Bitte keine Antworten sie zu sagen, eine Unterabfrage mit @count im Haupt Prädikat nur zu tun, da ich von dieser Lösung weiß, ist der Punkt, von diesem Post zu verstehen, wie das mit Prädikat in Kerndaten verwenden, was würde wahrscheinlich sowieso schneller als eine Unterabfrage. (Wenn Sie nicht erklären, warum ich keine Klausel haveing ​​verwenden kann)

Der folgende Code würde ein Array von Wörterbüchern mit der Anzahl der Bestellungen pro Bestellnummer zurückgeben. Was ich will, ist in der Lage sein, eine having -Klausel hinzufügen, um meine Anfrage zu beschränken nur die Wörterbücher für Objekte dieser Aufträge, die eine Zahl größer als 1 haben.

Hier ist der Code so weit und meine Versuche zu haben Prädikat:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"OrderedEntry" 
              inManagedObjectContext:context]; 
[fetchRequest setEntity:entity]; 
[fetchRequest setResultType:NSDictionaryResultType]; 

NSPredicate *predicate = [NSPredicate predicateWithFormat: 
       @"(status == %@)",[NSNumber numberWithInt:EntryStatusAlive]]; 


[fetchRequest setPredicate:predicate]; 


NSExpression *keyPathExpression = [NSExpression expressionForKeyPath: @"order"]; // Does not really matter 
NSExpression *maxExpression = [NSExpression expressionForFunction: @"count:" 
                 arguments: [NSArray arrayWithObject:keyPathExpression]]; 
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init]; 
[expressionDescription setName: @"orderCount"]; 
[expressionDescription setExpression: maxExpression]; 
[expressionDescription setExpressionResultType: NSInteger32AttributeType]; 

[fetchRequest setPropertiesToFetch: [NSArray arrayWithObjects:expressionDescription,@"order",nil]]; 


[fetchRequest setPropertiesToGroupBy:[NSArray arrayWithObjects:@"order",nil]]; 
//[fetchRequest setHavingPredicate:[NSPredicate predicateWithFormat:@"@count > 1"]]; 
//[fetchRequest setHavingPredicate:[NSComparisonPredicate predicateWithLeftExpression:maxExpression rightExpression:[NSExpression expressionForConstantValue:[NSNumber numberWithInteger:1]] modifier:NSDirectPredicateModifier type:NSGreaterThanPredicateOperatorType options:NSCaseInsensitivePredicateOption]]; 

NSError *error; 

NSArray * array = [context executeFetchRequest:fetchRequest error:&error]; 
+1

Haben Sie jemals eine Antwort auf diese interessiert jemand losgeht? Ich habe viele nutzlose Verweise auf "setHavingPredicate" gefunden, die keinen Hinweis darauf geben, wie das Format dieses Prädikats aussehen muss. Keine Arbeitsbeispiele, und nichts, was ich versucht habe, hat funktioniert ... –

+2

@ChristopherKing Nein, überhaupt nicht, ich habe im Grunde aufgegeben, es gibt keine Informationen im Web und die Apple Web Foren sind nicht hilfreicher. Ich glaube wirklich, dass niemand dies verwendet, da es sehr einfach ist, die gleiche Funktionalität des Having-Prädikats zu konstruieren, indem einfach ein normaler Abruf durchgeführt wird und dann mit einem Filter oder manuell mit einer Schleife durch die Daten verschoben wird. Wir wollen es wissen, denn es gibt immer den "richtigen Weg", etwas zu tun, besonders wenn die API zur Verfügung gestellt wird. – thewormsterror

Antwort

0

Erstens, wenn ich etwas analog zu versuchen, was du tust, ich erhalte eine Fehlermeldung, dass Sie nicht ein zu-viele-Beziehung zu setPropertiesToFetch: passieren können. Die NSFetchRequest documentation sichert dies ab: "Die Eigenschaftsbeschreibungen können Attribute, zu-eins-Beziehungen oder Ausdrücke darstellen." So das Problem # 1.

Problem # 2 ist, dass es scheint, dass Sie nicht Gruppe durch eine To-Viele-Beziehung entweder (dies ist nicht klar in der Dokumentation, aber Sie erhalten den gleichen Fehler und es macht auch Sinn).

Entfernen Sie "Reihenfolge" aus den Eigenschaften, die abgerufen werden sollen. Nach einem Attribut gruppieren. Ändern Sie das Hauptprädikat so, dass nur die von Ihnen gruppierten Attribute einbezogen werden (oder entfernen Sie es einfach). Geben Sie im Prädikat "Haben" eine "Reihenfolge" an.

[fetchRequest setPropertiesToGroupBy: @[ @"???" ]]; 
[fetchRequest setHavingPredicate: [NSPredicate predicateWithFormat: @"[email protected] > 1"]]; 

Jetzt werden Sie die Anfrage sehen wird funktionieren, aber die Ergebnisse waren wahrscheinlich nicht das, was Sie erwartet hatten:

- NSArray 
    - NSDictionary { status = @"alive", orderCount = "4" } 
    - NSDictionary { status = @"alive", orderCount = "9" } 
    - NSDictionary { status = @"alive", orderCount = "2" } 
    - etc... 

NSDictionaryResultType eigentlich nicht geben Ihnen etwas durch die Objekte zu identifizieren - es gibt dir nur die Werte.

Also ist Ihr nächster Schritt, IDs für diese OrderedEntry Objekte zurückzubekommen. Der Trick ist include an expression, die Ihnen die NSManagedObjectID als Schlüssel in jedem Wörterbuch zurückgeben wird.

Ich weiß nicht, ob dies tatsächlich eine verbesserte Leistung überhaupt (über nur AND-in es in das Hauptprädikat) geben wird. Meiner Erfahrung nach besteht eine der besten Möglichkeiten zur Verbesserung der Abrufleistung darin, Singleton-NSPredicates zu erstellen und Substitutionsvariablen zum Einrichten jedes Abrufs zu verwenden. Prädikat-Parsing kann teuer sein.

Wörterbuch Ergebnisarten können ein Schmerz sein. Normalerweise ist es einfach besser, ein gutes Prädikat zu konstruieren. Ich neige dazu, sie nur für Ausdrücke zu verwenden (d. H. Statistische Berechnungen im Diagramm durchzuführen, die einen Wert zurückgeben). Wenn Sie sich alle Einschränkungen bei den Eigenschaften zum Abrufen und Gruppieren nach und die Prädikatbeschränkungen ansehen, scheint dies der von Apple beabsichtigte Zweck zu sein.Ich bin mir nicht einmal sicher, ob es möglich ist, das zu tun, was Sie tun wollen, indem Sie ein Prädikat zum Haben gruppieren und verwenden - zum Beispiel, nach was werden Sie gruppieren? Wenn nach Status (den Sie gruppieren müssen, um es in Ihr Prädikat aufzunehmen), werden dann nicht alle OrderEntries kollabiert, und Sie erhalten nicht die separaten objectIDs und orderCounts? Es ist am besten, sich an das Hauptprädikat zu halten, nicht zu gruppieren und Prädikate zu haben.

+0

Ich verstehe nicht, was Sie sagen, SetPropertiesToFetch: Was mache ich hier falsch? Ich habe ein Attribut "order" und eine expressionDescription, die ein Ausdruck ist. – thewormsterror

+0

für Problem Nummer 2 meine Bestellung ist ein Attribut, keine Beziehung, so kann ich von meinem Verständnis nach gruppieren. – thewormsterror

+0

Wie erwarten Sie dann ein Attribut zu zählen? Die Reihenfolge muss für Ihr Beispiel oben eine To-Viele-Beziehung sein, um überhaupt einen Sinn zu ergeben. – karwag

1

landete ich mit diesem für

-(BOOL)ordersAreSaneOnDay:(NSNumber*)dayNumber forUser:(User*)user inContext:(NSManagedObjectContext*)context { 
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"BasicEntry" 
              inManagedObjectContext:context]; 
[fetchRequest setEntity:entity]; 
[fetchRequest setResultType:NSDictionaryResultType]; 

NSPredicate *predicate = [NSPredicate predicateWithFormat: 
       @"(status == %@) && ((type != %@) && (type != %@) && (dayNumber == %@)) && ((user == NIL) || (user == %@))",[NSNumber numberWithInt:EntryStatusAlive],[NSNumber numberWithInt:EntryTypeTask],[NSNumber numberWithInt:EntryTypeCompletedTask],dayNumber,user]; 


[fetchRequest setPredicate:predicate]; 


NSExpression *keyPathExpression = [NSExpression expressionForKeyPath: @"order"]; // Does not really matter 
NSExpression *maxExpression = [NSExpression expressionForFunction: @"count:" 
                 arguments: [NSArray arrayWithObject:keyPathExpression]]; 
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init]; 
[expressionDescription setName: @"orderCount"]; 
[expressionDescription setExpression: maxExpression]; 
[expressionDescription setExpressionResultType: NSInteger32AttributeType]; 

[fetchRequest setPropertiesToFetch: [NSArray arrayWithObjects:expressionDescription,@"order",nil]]; 
[expressionDescription release]; 

[fetchRequest setPropertiesToGroupBy:[NSArray arrayWithObjects:@"order",nil]]; 
//[fetchRequest setHavingPredicate:[NSPredicate predicateWithFormat:@"[email protected] > 1"]]; 
//[fetchRequest setHavingPredicate:[NSComparisonPredicate predicateWithLeftExpression:maxExpression rightExpression:[NSExpression expressionForConstantValue:[NSNumber numberWithInteger:1]] modifier:NSDirectPredicateModifier type:NSGreaterThanPredicateOperatorType options:NSCaseInsensitivePredicateOption]]; 

NSError *error; 

NSArray * array = [context executeFetchRequest:fetchRequest error:&error]; 
array = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"orderCount > 1"]]; 
//NSLog(@"it worked %@",array); 
[fetchRequest release]; 

if ([array count]) return FALSE; 
return TRUE; 

}

Verwandte Themen