как я могу поместить все запросы на выборку в Core Data DAL? - PullRequest
1 голос
/ 13 июля 2010

Абсолютно новый для Objective-C и Core Data, исходящий из .net фона. Я действительно хочу поместить все свои запросы на выборку в какой-то класс, который я могу вызвать, предпочтительно статически, чтобы получить мои объекты, что-то вроде:

ObjectType * myObject = [CoreDataDAL GetObject: ID];

У кого-нибудь есть шаблон для реализации этого?

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

Eidt: Вот мой код в его нынешнем виде - кажется, он отлично работает - пожалуйста, разорвите его, если я иду по неправильному пути - вот основной DAL:

#import "CoreDataDAL.h"
#import "CoreDataAppDelegate.h"

@implementation CoreDataDAL

@synthesize managedObjectContext;

-(id)init {
    if (self=[super init]) {
        CoreDataAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
        self.managedObjectContext = appDelegate.managedObjectContext;
    }
    return self;
}

-(Client *) GetClient:(NSString *) ClientID{
    /* Client Fetch Request */
    NSFetchRequest *request = [[NSFetchRequest alloc]init];
    NSEntityDescription *entityType = [NSEntityDescription entityForName:@"Client" inManagedObjectContext:managedObjectContext];
    [request setEntity:entityType];
    NSPredicate *predicate =[NSPredicate predicateWithFormat:@"ClientID==%@",ClientID];
    [request setPredicate:predicate];

    NSError *error;
    NSArray *entities = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];

    return [entities objectAtIndex:0];
}

@end

А вот как это используется в моих контроллерах вида:

CoreDataDAL *dal = [[CoreDataDAL alloc]init];
Client *client = [dal GetClient:clientID];
[dal release];

Кажется, достаточно прямо, мысли?

Ответы [ 2 ]

14 голосов
/ 14 июля 2010

Не делай этого;то, что вы делаете, это перенос шаблона из одного контекста в другой, где он на самом деле не имеет смысла.

Во-первых, вам вообще не следует моделировать идентификаторы в Core Data;Фреймворк делает это для вас уже с NSManagedObjectID.Таким образом, метод -clientWithID: в классе CoreDataDAL является избыточным.(Обратите внимание, что я также изменил имя вашего гипотетического метода в соответствии с надлежащими соглашениями об именах Какао.) Вместо этого вы можете просто использовать -[NSManagedObjectContext objectWithID:] или -[NSManagedObjectContext existingObjectWithID:error:], чтобы получить объект на основе его NSManagedObjectID.

Точно так же управление отношениями обрабатывается для вас.Вам не нужно иметь метод в вашем DAL, который может (скажем) извлечь все экземпляры Address, которые применяются для данного клиента, путем оценки некоторого запроса.Вы можете просто пройти через отношение вашего Клиента ко многим addresses, чтобы получить к ним доступ, и напрямую управлять теми же отношениями (вместо установки внешних ключей и т. Д.).

Наконец, если вы действительно хотите иметь методычтобы выполнить специализированные запросы, вы можете либо указать запрос через выбранное свойство в соответствующей сущности для его результатов, либо вы можете добавить этот метод непосредственно в соответствующий класс .Методы класса в Objective-C не похожи на статические методы в C ++, Java или C # - их можно переопределить так же, как это делают методы экземпляра, и они гораздо более подходят для этого вида использования.

Например, скажему вашего объекта Client есть свойство syncID, представляющее идентификатор объекта, который он представляет в каком-либо веб-сервисе.(Обратите внимание, что это специально для привязки локального объекта к удаленному объекту, а не к «первичному ключу» локального объекта.) Вероятно, у вас есть методы класса в классе MyClient, связанные с вашей клиентской сущностью, например:

@implementation MyClient

+ (NSString *)entityClassName
{
    return @"Client";
}

+ (NSEntityDescription *)entityInManagedObjectContext:(NSManagedObjectContext *)context
{
    return [NSEntityDescription entityForName:[self entityClassName] inManagedObjectContext:context];
}

+ (MyClient *)clientWithSyncID:(NSString *)syncID
        inManagedObjectContext:(NSManagedObjectContext *)context
                         error:(NSError **)error
{
    MyClient *result = nil;

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:[self entityInManagedObjectContext:context]];
    [request setPredicate:[NSPredicate predicateWithFormat:@"syncID == %@", syncID]];
    [request setFetchLimit:1];

    NSArray *results = [context executeFetchRequest:request error:error];
    if ([results count] > 0) {
        result = [results objectAtIndex:0];
    } else {
        if (error != NULL) {
            *error = [NSError errorWithDomain:MyAppErrorDomain
                                         code:MyAppNoClientFoundError
                                     userInfo:nil];
        }
    }

    return result;
}

@end

Это похоже на то, что вы написали в своем классе DAL, но вместо того, чтобы объединять все выборки в одном месте, он помещает логику для выборок, соответствующих определенному классу управляемых объектов в этом классе, который действительногде это принадлежит.Благодаря тому, что в Objective-C есть настоящие методы класса, вы можете поместить методы, такие как +entityInManagedObjectContext: и +entityClassName, в общий базовый класс, а затем переопределить только последний в зависимости от обстоятельств в подклассах (или даже сгенерировать соответствующее имя сущности).от имени класса).

Подводя итог:

  • Не воссоздайте то, что Core Data уже реализует для вас с точки зрения таких вещей, как идентификаторы объектов, управление отношениями и т. д..
  • Используйте полиморфизм как на уровне класса , так и для поддержания чистоты кода, а не используйте "служебные" классы, такие как "слои доступа к данным".
1 голос
/ 13 июля 2010

Запрос на выборку должным образом принадлежит отдельным контроллерам в шаблоне Model-View-Controller.Выборка возвращает конкретную информацию в определенном порядке, требуемом для каждого отдельного представления.Каждый выбор настраивается для нужд каждого конкретного представления.Таким образом, помещение всех выборок приложения в один объект нарушит инкапсуляцию, а не улучшит ее.Только извлеченные свойства и извлеченные отношения принадлежат самой модели данных.

Контекст управляемого объекта выполняет функцию объекта данных в простых приложениях.Он реализует все функции, необходимые для получения и извлечения информации из стека базовых данных, например - objectWithID:.В большинстве случаев все, что вам нужно сделать, это передать контекст контроллерам и позволить им настроить выборки для него.

Если ваше приложение большого размера или имеет несколько контекстов, вы всегда можете заключить контекст / ы в собственный класс менеджера с различными средствами доступа и удобными методами, чтобы сделать операции с базовыми данными более плавными.Вы можете законным и безопасным образом реализовать класс менеджера как единое целое, чтобы упростить доступ к нему в любом месте приложения.

Редактировать:

Код выглядит хорошо, за исключением изменяемой копии.Это бессмысленно и приведет к утечке памяти.Массив entities необходим только для одной строки, и это является автоматическим выпуском.Хранение объектов Client управляется контекстом.Вы должны проверить ошибку и, по крайней мере, зарегистрировать ее для отладки.

Вы хотите избежать "get" и "set" для имен методов, которые не являются средствами доступа.Среда выполнения ищет методы, которые начинаются с «get» и «set» для поиска методов доступа.По соглашению все имена методов начинаются со строчной буквы.Возможно, вы захотите сделать имя метода более описательным, чтобы оно автоматически комментировалось, когда вы читаете его в будущем.

Итак:

[theCoreDataDal GetClient:vaugelyNamedString];

до

[theCoreDataDal clientWithClientID:vaugelyNamedString];

Проблема, с которой вы столкнетесь при попытке втиснуть все в один объект, состоит в том, что выборки обычно уникальны инастроен для нужд конкретного интерфейса.Более того, вы обычно начинаете с выборки, чтобы найти конкретные объекты, но затем вы проводите остальное время, гуляя по отношениям, основанным на неизвестном вводе, до времени выполнения.

Базовые данные - это уровень доступа к данным.Большая часть кода, который вы пишете для Core Data, на самом деле является кодом контроллера.Нет ничего концептуально проблемного в этом GetClient методе, кроме как часто вы собираетесь выполнять эту конкретную выборку?

Когда я создаю объект Data Model Manager, я использую его в основном для хранениякод котельной плиты.Например, хотя каждый запрос на выборку уникален, все они начинаются одинаково с описанием сущности, поэтому я автоматически генерирую методы для возврата базовой выборки для каждой сущности и помещаю ее в менеджер.Тогда у меня есть другой метод котельной пластины, чтобы фактически выполнить выборку.При использовании контроллер запрашивает у менеджера объект выборки для конкретной сущности.Контроллер настраивает выборку и затем отправляет ее обратно менеджеру, чтобы выполнить выборку и вернуть результаты.

Все котельные находятся в диспетчере, а все настроенное - в контроллере.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...