2. Что такое ActiveRecord?
ActiveRecord - паттерн, описанный Мартином Фаулером в книге
«Patterns of Enterprise Application Architecture» (Шаблоны
корпоративных приложений). AR является популярным
способом доступа к данным реляционных баз данных в
объектно-ориентированном программировании.
Объект, выполняющий роль оболочки для строки таблицы или
представления базы данных. Он инкапсулирует доступ к базе
данных и добавляет к данным логику домена.
3. ● Пусть существует таблица в базе данных. Для данной
таблицы создаётся специальный класс AR, являющийся
отражением (представлением) таблицы, таким образом,
что:
● каждый экземпляр данного класса соответствует одной
записи таблицы;
● при создании нового экземпляра класса (и заполнении
соответствующих полей) в таблицу добавляется новая
запись;
● при чтении полей объекта считываются соответствующие
значения записи таблицы баз данных;
● при изменении (удалении) какого-либо объекта
изменяется (удаляется) соответствующая ему запись.
4. Core Data и Active Record
Core Data основана на паттерне Active Record, но для работы с
базой данных приходится писать довольно громоздкий код.
Пример Apple:
NSManagedObjectContext *moc = [self managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Employee"
inManagedObjectContext:moc];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];
// Set example predicate and sort orderings...
NSNumber *minimumSalary = ...;
NSPredicate *predicate = [NSPredicate predicateWithFormat:
@"(lastName LIKE[c] 'Worsley') AND (salary > %@)", minimumSalary];
[request setPredicate:predicate];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"firstName"
ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
NSError *error = nil;
NSArray *array = [moc executeFetchRequest:request error:&error];
if (array == nil){
// Deal with error...
}
5. Как видно из примера для поиска в базе данных
Сотрудников(Employee) у которых фамилия содержит
«Worsley» и зарплата выше минимальной зарплаты приходится
писать много «лишнего» кода.
Решение данной проблемы предоставили Magical Panda в
своей библиотеке ActiveRecord for Core Data
Вот тот же пример, только с использованием ActiveRecord for
CoreData(MagicalRecord):
NSNumber *minimumSalary = ...;
NSPredicate *predicate = [NSPredicate predicateWithFormat:
@"(lastName LIKE[c] 'Worsley') AND (salary > %@)", minimumSalary];
NSArray *employees = [Employee MR_findAllSortedBy:@"firstName"
asceding:YES
withPredicate:predicate];
6. ActiveRecord for Core Data позволяет:
1. Сделать чище код по работе с Core Data
2. Позволяет делать простые однострочные
запросы
3. Несмотря на простоту, позволяет
модифицировать NSFetchRequest, когда
запрос нуждается в модификации.
7. Примеры использования.
Допустим есть класс Song с полями id, length и name:
@interface Song : NSManagedObject
@property (nonatomic, retain) NSNumber * length;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSNumber * unid;
@end
@implementation Song
@dynamic length;
@dynamic name;
@dynamic unid;
@end
8. Если необходимо найти все Song объекты в базе данных, то
вызов будет иметь следующий вид:
NSArray *songs = [Song MR_findAll];
Поиск песен, отсортированных по name будет иметь вид:
NSArray *songs = [Song MR_findAllSortedBy:@"name" ascending:YES];
Если есть песня с уникальным значением атрибута, то
можно воспользоваться функцией:
NSArray *songs = [Song MR_findFirstByAttribute:@"name" withValue:@"Imagine"];
Так же ActiveRecord for Core Data позволяет использовать
NSPredicate:
NSPredicate *songFilter = [NSPredicate predicateWithFormat:@"length > %@", @""];
NSArray *songs = [Song MR_findAllWithPredicate:songFilter];
10. Редактирование данных:
Создать запись в базе данных при помощи ActiveRecord for
Core Data очень просто:
Song *song = [Song MR_createEntity];
Занимает очень мало кода в отличии от этого примера:
Song *song = (Song *)[NSEntityDescription insertNewObjectForEntityForName:@"Song"
insertNewObjectForEntityForName:[ self managedObjectContext]];
Удаление:
[song MR_deleteEntity]; [Song truncateAll];
Редактирование аттрибутов:
Song *song = [Song MR_createEntity];
song.name = @"stairway to heaven";
song.length = [NSNumber numberWithInt:150];
После редактирования данных необходимо сохранить контекст:
[[NSManagedObjectContext defaultContext] MR_save];
11. Подключение к проекту:
Добавляем в MyProjectName-Prefix.pch
#import "CoreData+ActiveRecordFetching.h"
В AppDelegate в application:didFinishLaunchingWithOptions: добавлям
вызов
[ActiveRecordHelpers
setupCoreDataStackWithAutoMigratingSqliteStoreNamed:@"MyProject.sqlite"];
Данный метод создаст NSPersistentStore с указанным именем и файлом
модели .xcdatamodeld который найдет в бандле приложения.
12. Default Managed Object Context
При работе с Core Data используется объект
NSManagedObjectContext. ActiveRecord for Core Data позволяет
установить DefaultContext, который будет NSManagedObjectContext по-
умолчанию для всего приложения. Создание NSManagedObjectContext
для использования в других потоках выглядит следующим
образом:
NSManagedObjectContext *myNewContext = [NSManagedObjectContext newContext];
Этот контекст можно сделать по-умолчанию, и тогда он будет
использоваться во всех запросах, если в названии метода
запроса вконце не стоит «inContext:». Рекомендуется создавать и
устанавливать контекст по-умолчанию только в главном потоке.
13. Источники
● https://github.com/magicalpanda/MagicalRecord
● http://ru.wikipedia.org/wiki/ActiveRecord
● http://habrahabr.ru/blogs/macosxdev/130262/
● «Patterns of Enterprise Application Architecture» (англ.
Шаблоны корпоративных приложений)