2016-05-28 6 views
0

Мои отношения показаны на рисунке ниже.CoreData Сортировать по соотношению

CoreData relation

Я хотел бы сортировать события сначала те, которые находятся в активном продвижении, а затем по дате начала. Акция активна, если текущая дата находится между датой начала и окончания. К сожалению, из-за CoreData я не могу использовать переходные свойства для сортировки. В моем контроллере я не использую контроллер выборки.

Есть ли способ достичь этого?

Обновление:

Я после сортировки Дескрипторы:

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

Предикаты (Они в порядке, хотя):

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) 

И это Request (I используя концепцию CoreStore, но идея должна быть ясной):

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

Да. Но если вам нужна дополнительная помощь, покажите код (и язык, на котором вы хотите это сделать). – sschale

+0

Спасибо, я использую Swift, но язык для меня не важен. Завтра я обновляю свой ответ простым кодом. – apetrov

+0

Что не работает? – Fogmeister

ответ

1

Как я понял, вы должны получить все Event объектов, но в порядке. Для того, чтобы сделать это с такой сложной для того, что включает в себя отношения, насколько я знаю, вы должны извлечь все события, а затем отсортировать их, используя NSArray's метод

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

Вот куски кода

1 . Выборка из основных данных

// 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 производится вручную с помощью основных методов, и вы можете использовать Magical Record или любую другую структуру, которая работает с Core Data, чтобы сделать его в ряд.

2. Сортировка результатов

__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. Дополнительный метод для работы с NSDate

Этот метод был использован в метод сортировки

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

Я could't проверьте код по понятным причинам, поэтому извините за любые опечатки, если они есть.

+0

Спасибо, я очень ценю ваш ответ. Я уже использую библиотеку третьей части (CoreStore), но ваш код ясен и абсолютно читаем. Я собираю данные по партиям, поэтому после каждой новой партии мне нужно ее отфильтровать. Поэтому, вероятно, я должен принять в другом направлении и попробовать другую структуру для моего результата (отсортированный массив). – apetrov

1

Я предлагаю вам создать свойство «isActive» для пересечения в Entity Promotion для расчета активной записи.

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]]; 

После этого вы можете отфильтровать результат выборки путем сортировки:

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

HTH.

+0

Я думал о применении фильтра по выбранным результатам. Однако я получаю ограничение (разбиение на страницы), и, если я получу это правильно, я должен применить фильтр ко всем событиям, которые у меня уже есть не только до последней партии. Это может быть немного медленнее, но я попробую. – apetrov

Смежные вопросы