2016-05-28 6 views
0

Meine Beziehung ist auf dem Bild unten gezeigt.CoreData Nach Beziehung sortieren

CoreData relation

Ich mag Events von denen zuerst sortieren, die in der aktiven Förderung sind und dann nach Startdatum. Die Werbeaktion ist aktiv, wenn das aktuelle Datum zwischen dem Start- und Enddatum liegt. Leider kann ich aufgrund von CoreData keine transienten Eigenschaften zum Sortieren verwenden. In meinem Controller verwende ich keinen Abruf-Controller.

Gibt es eine Möglichkeit, das zu erreichen?

Update:

Ich habe folgende Art Deskriptoren:

// First is incorrect 
[NSSortDescriptor(key: "promotion.start", ascending: false), 
NSSortDescriptor(key: "start", ascending: true)] 

Prädikate (Sie sind in Ordnung, obwohl):

let promotionsPredicate = 
    NSPredicate(format: "(%@ >= promotion.start && %@ <= promotion.end) && " + 
       "(ANY promotion.cities.id == %@)", NSDate(), NSDate(), objectID) 
let eventsPredicate = 
    NSPredicate(format: "start >= %@ && venue.city.id == %@", 
           NSDate(), objectID) 

let subpredicates = [eventsPredicate, promotionsPredicate]      
let compoundPredicate NSCompoundPredicate(orPredicateWithSubpredicates: subpredicates) 

Und dies ist der Antrag (I verwende CoreStore, aber die Idee sollte klar sein):

class func pagedEventsForPredicateSortedByInPromoAndStartDate(predicate: NSPredicate, 
                   descriptors: [NSSortDescriptor], 
                   fetchOffset: Int, 
                   fetchLimit: Int) -> [Event] { 

    return CoreStore.fetchAll(From(Event), 
           Where(predicate), 
           OrderBy(descriptors), 
           Tweak { (fetchRequest) -> Void in 
           fetchRequest.fetchOffset = fetchOffset 
           fetchRequest.fetchLimit = fetchLimit 
           fetchRequest.returnsObjectsAsFaults = false 
     }) ?? [] 
} 
+0

Ja. Aber wenn Sie mehr Hilfe benötigen, zeigen Sie etwas Code (und die Sprache, in der Sie es tun möchten). – sschale

+0

Danke, ich benutze Swift, aber Sprache ist nicht wichtig für mich. Ich werde morgen meine Antwort mit einem einfachen Code aktualisieren. – apetrov

+0

Was funktioniert nicht? – Fogmeister

Antwort

1

Wie ich verstanden habe, müssen Sie alle Event Objekte, aber nur in der richtigen Reihenfolge. Um das zu tun mit solch komplizierten Ordnung umfasst diese Beziehung, soweit ich weiß, Sie haben, um alle Ereignisse zu holen und dann sortieren sie mit NSArray's Methode

- (NSArray<ObjectType> *)sortedArrayUsingComparator:(NSComparator)cmptr 

Hier sind die Stücke des Codes

1 Fetch. von Core Data

// get the right context here 
NSManagedObjectContext *yourContext; 

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Event"]; 
// extra line, predicate is nil by default, any other required predicate could be written here 
request.predicate = nil; 

__block NSArray *results = nil; 
[yourContext performBlockAndWait:^{ 

    NSError *error = nil; 
    results = [yourContext executeFetchRequest:request error:&error]; 

     if (error) { 
      // handle error here 
     } 
    }];

Fetch manuell mit Kernmethoden hergestellt und Sie können Magical Record oder andere Rahmen verwenden, die mit Core Data arbeitet es in einer Reihe zu machen.

2. Ordnen Sie die Ergebnisse

__weak typeof(self) weakSelf = self; 

NSDate *now = [NSDate date]; 
NSArray *sortedResults = [results sortedArrayUsingComparator:^NSComparisonResult(Event *_Nonnull obj1, Event *_Nonnull obj2) { 

    BOOL isObj1InActivePromotion = [weakSelf date:now isBetweenDate:obj1.promotion.start andDate:obj1.promotion.end]; 
    BOOL isObj2InActivePromotion = [weakSelf date:now isBetweenDate:obj2.promotion.start andDate:obj2.promotion.end]; 

    // if they eather are in active promotion or no, just compare them by start date of the Event 
    if (isObj1InActivePromotion == isObj2InActivePromotion) { 
     return [obj1.start compare:obj2.start]; 
    } else { 
     return isObj1InActivePromotion ? NSOrderedAscending : NSOrderedDescending; 
    } 
}]; 

3. Zusätzliche Verfahren mit NSDate zur Arbeit wurde in Sortierverfahren could't

+ (BOOL)date:(NSDate *)date isBetweenDate:(NSDate *)beginDate andDate:(NSDate *)endDate 
{ 
    if ([date compare:beginDate] == NSOrderedAscending) { 
     return NO; 
    } 

    if ([date compare:endDate] == NSOrderedDescending) { 
     return NO; 
    } 

    return YES; 
} 

I

Diese Methode verwendet überprüfen Sie den Code aus offensichtlichen Gründen, so dass Tippfehler, wenn sie sind.

+0

Danke, ich schätze deine Antwort sehr. Ich benutze bereits eine dritte Teilbibliothek (CoreStore), aber Ihr Code ist klar und absolut lesbar. Ich hole Daten in Batches, daher muss ich sie nach jedem neuen Batch filtern. Also sollte ich wahrscheinlich in eine andere Richtung gehen und für mein Ergebnis eine andere Struktur ausprobieren (sortiertes Array). – apetrov

1

Ich schlage vor, Sie erstellen "isActive" Durchtrennung Eigenschaft in Promotion Entity zur Berechnung aktiver Datensatz.

NSPredicate *predicate = [NSPredicate predicateWithFormat:@“isActive == %@", @1]; 
     NSMutableArray *finalResult = [NSMutableArray arrayWithArray:[results filteredArrayUsingPredicate:predicate]]; 

HTH:

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Event"]; 
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] 
            initWithKey:@“start” ascending:YES]; 
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]]; 
[fetchRequest setIncludesPropertyValues:YES]; 
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]]; 

Danach können Sie durch Sortieren Ergebnis filtern holen.

+0

Ich dachte über Filter auf die abgerufenen Ergebnisse anwenden. Allerdings hole ich mit Limit (Paginierung) und, wenn ich das richtig mache, sollte ich Filter auf alle Ereignisse anwenden, die ich nicht nur bis zum letzten Batch habe. Es mag ein bisschen langsam sein, aber ich werde es versuchen. – apetrov