Самый быстрый способ проверить, существует ли объект в Базовых данных или нет? - PullRequest
53 голосов
/ 12 февраля 2010

Я хочу посмотреть, сохраняется ли объект в Базовых данных или нет. Например, у меня есть друзья в основных данных, и я идентифицирую их по имени. Я могу запросить основные данные, чтобы узнать, известен ли «Джордж». Если массив результирующего набора содержит больше нуля объектов, я знаю, что Джордж там. Но Core Data загружает все это в память, и я просто хочу знать, хранится ли Джордж или нет.

Как бы я сделал это наиболее эффективным способом?

Ответы [ 5 ]

96 голосов
/ 12 февраля 2010

Настройте запрос базовых данных и вместо фактической выдачи запроса сделайте следующее:

NSError *error = nil;
NSUInteger count = [managedObjectContext countForFetchRequest:request
                                                        error:&error];
if (!error) {
    return count;
} else {
  return 0;
}

На практике метод countForFetchRequest:error: возвращает количество объектов, которые возвращал бы данный запрос выборки.если оно было передано executeFetchRequest:error:.


Редактировать: (по Regexident)

As Джош Кэсвелл правильно прокомментировал, правильный способ обработки ошибок является либо:

if (count == NSNotFound) {
    NSLog(@"Error: %@", error);
    return 0;
}
return count;

или это (без регистрации ошибок):

return (count != NSNotFound) ? count : 0;
25 голосов
/ 15 декабря 2012

Да, безусловно, есть лучший метод. Настройте запрос на выборку как обычно, но вместо того, чтобы фактически выполнить его, просто запросите количество объектов, которые он возвратил бы, если бы он был передан executeFetchRequest: error:

Это можно сделать с помощью

- (NSUInteger)countForFetchRequest:(NSFetchRequest *)request error:(NSError **)error;

Примерно так:

- (int) numberOfContacts{

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSManagedObjectContext *managedObjectContext = yourManagedObjectContext;
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Contacts" inManagedObjectContext:managedObjectContext];
    [request setEntity:entity];

    NSError *error = nil;
    NSUInteger count = [managedObjectContext countForFetchRequest:request error:&error];
    [request release];

    if (!error){
        return count;
    }
    else
        return -1;

}
7 голосов
/ 20 февраля 2015

Если цель состоит в том, чтобы проверить, существует ли объект, решение состоит в том, чтобы реализовать этот метод в модели вашего друга:

-(BOOL)exist
{
    NSManagedObjectContext *managedObjectContext = yourManagedObjectContext;
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Friends" inManagedObjectContext:managedObjectContext];

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entity];
    [request setFetchLimit:1];
    [request setPredicate:[NSPredicate predicateWithFormat:@"firstName == %@", self.firstName]];    

    NSError *error = nil;
    NSUInteger count = [managedObjectContext countForFetchRequest:request error:&error];

    if (count)
    {
        return YES;
    }
    else
    {
        return NO;
    }
}
6 голосов
/ 28 октября 2011

Согласно Core Data Documentation , вам не следует продолжать выборку, чтобы увидеть, существуют ли объекты.

Есть много ситуаций, когда вам может понадобиться найти существующие объекты (объекты, уже сохраненные в магазине) для набора дискретных входных значений. Простое решение состоит в том, чтобы создать цикл, затем для каждого значения по очереди выполнить выборку, чтобы определить, существует ли соответствующий сохраняемый объект и так далее. Этот шаблон не хорошо масштабируется. Если вы профилируете свое приложение с этим шаблоном, вы обычно находите выборку одной из более дорогих операций в цикле (по сравнению с простой итерацией по коллекции элементов). Хуже того, этот шаблон превращает проблему O (n) в проблему O (n ^ 2).

Редактировать 16 марта :
Я не эксперт по БД, но, поскольку люди просят более эффективного решения, рассмотрим этот набор:

set1 = [apple, orange, banana, pineapple, lettuce]

Мы хотим выяснить, входит ли [mango, apple, grape] в этот набор.

В документах говорится, что мы не должны перебирать [манго, яблоко, виноград] и запрашивать базу данных, ища каждый элемент по очереди, потому что это медленно.

Рассмотрим это решение:

Хэш-наборы на стороне сервера:

hash([mango, apple, grape]) = 234095dda321affe...

Затем вы можете полностью обойти Базовые данные, спросив сервер, если что-то изменилось. Если наборы отличаются, вы можете вывести объекты в контекст управляемого объекта и выполнить массовое сохранение.

Если вы действительно хотите увидеть, является ли каждый объект по очереди частью набора, вы можете сделать выборку на основе индексированной характеристики, такой как «фрукты с кожурой».

0 голосов
/ 06 мая 2019

Обновление до SWIFT 5:

func checkIfItemExist(id: Int, type: String) -> Bool {

    let managedContext = CoreDataStack.sharedInstance.persistentContainer.viewContext
    let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "DetailsEntity")
    fetchRequest.fetchLimit =  1
    fetchRequest.predicate = NSPredicate(format: "id == %d" ,id)
    fetchRequest.predicate = NSPredicate(format: "type == %@" ,type)

    do {
        let count = try managedContext.count(for: fetchRequest)
        if count > 0 {
            return true
        }else {
            return false
        }
    }catch let error as NSError {
        print("Could not fetch. \(error), \(error.userInfo)")
        return false
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...