Продолжаем изучать CoreData.
Сегодня урок посвященный связям между сущностями в базе данных.
Видео с уроком находится здесь.
Продолжаем проект, созданный в прошлом уроке (можно скачать в уроке 42).
Мы создали новый объект - студент, сохранили его в базу.
Создали запрос в базу данных и вывели всех студентов в массив.
Для удаления всех студентов - помечаем их на удаление и сохраняем контекст:
А также есть проперти у NSFetchRequest:
Сегодня урок посвященный связям между сущностями в базе данных.
Видео с уроком находится здесь.
Продолжаем проект, созданный в прошлом уроке (можно скачать в уроке 42).
Мы создали новый объект - студент, сохранили его в базу.
Создали запрос в базу данных и вывели всех студентов в массив.
Для удаления всех студентов - помечаем их на удаление и сохраняем контекст:
for (TAStudent *student in arrayResult) {
NSLog(@"%@ %@ = %@",
student.firstName,
student.lastName,
student.score);
[self.managedObjectContext deleteObject:student];
}
[self.managedObjectContext save:nil];
Для удаления большого количества студентов (если нам не нужны их проперти и нужно сократить время) нужно запрещать парсить проперти.
В прошлом уроке рассматривали этот вопрос:
[request setResultType:NSDictionaryResultType];
[request setResultType:NSDictionaryResultType];
А также есть проперти у NSFetchRequest:
@property (nonatomic) BOOL includesSubentities
@property (nonatomic) BOOL includesPropertyValues
Перенесем код в функции: запрос, вывод, удаление:
- (NSArray *)requestAllStudents
{
NSFetchRequest *request = [[NSFetchRequest alloc]init];
NSEntityDescription *description = [NSEntityDescription entityForName:@"TAStudent" inManagedObjectContext:self.managedObjectContext];
[request setEntity:description];
NSError *requestError = nil;
NSArray *arrayResult = [self.managedObjectContext executeFetchRequest:request error:&requestError];
if (requestError) {
NSLog(@"Request Error: %@", [requestError localizedDescription]);
}
return arrayResult;
}
- (void)printAllObjects
{
NSArray *arrayResult = [self requestAllStudents];
for (TAStudent *student in arrayResult) {
NSLog(@"%@ %@ = %@",
student.firstName,
student.lastName,
student.score);
}
}
- (void)deleteAllStudents
{
NSArray *arrayResult = [self requestAllStudents];
for (TAStudent *student in arrayResult) {
[self.managedObjectContext deleteObject:student];
}
[self.managedObjectContext save:nil];
}
Создадим новую сущность - автомобиль и назовем ее: TACar.
Создадим атрибут model типа String.
Студенту добавим связь - carRelation в Destination указываем TACar.
Указываем тип связи To One - один студент имеет одну машину.
В сущности TACar создаем ответную связь owner на студента и указываем связь To One. Машина имеет только одного владельца - студента.
Теперь определим тип правила удаления для TAStudent:
Nulify - это правило означает, что при удалении студента связь owner у соответствующей машины станет Null.
Если установить тип правила удаления - Cascade, то при удалении студента соответствующая машина тоже будет удалена.
Тип Deny означает, что если к примеру у студента есть 10 машин, то студент не удалится, пока не удалятся все его машины. Но иногда с ней происходят глюки (не рекомендуется использовать).
NoAction - ничего не происходит при удалении.
Нам для TAStudent по логике больше подходит Cascade. Если уходит (удаляется) студент, то сведения об его машине нам не нужны, т.е. TACar соответствующая тоже удаляется.
Для TACar выставляем правило для удаления - Nulify. Т.к. если удаляется машина, то студент может остаться.
Мы поменяли сущности и связи, пересоздадим класс для студента и машины. Для этого выделяем 2 сущности и нажимаем file-> new->file->core data->NSManagedObject subclass.
XCode автоматически сгенерирует файлы для классов в соответствии с настройками в модели.
Теперь у нас появилось 2 сущности TAStudent и TACar.
Чтобы вывести все объекты из базы за один запрос, необходимо создать базовую (родительскую сущность) и от нее унаследовать наши классы студента и машины.
Создаем родительскую сущность TABaseObject.
А для класса TAStudent и TACar выставляем родителя: Parent Entity - TABaseObject.
Теперь делаем методы для вывода всех объектов и удаления всех объектов:
Для добавления связи, т.е. чтобы студент стал владельцем машины. Создаем студента, машину, указываем в carRelation новую машину и сохраняем контекст:
Для удобного вывода определим методы вывода для каждой сущности:
Для проверки перед удалением определим метод в TAStudent.m для TAStudent и аналогичный для TACar:
Перед удалением студента вызвался этот метод для машины и студента (по логам).
При удалении машины, метод вызвался только для машины.
Это происходит по тому, что для студента правило удаления стоит Cascade, а для машину Nulify.
Можно поместить этот метод в базовый класс TABaseObject.m
Проверим как работает связь один ко многим.
Для этого создадим новую сущность TAUniversity. Определим связь со студентами один ко многим (университет имеет много студентов) и правило удаление - Cascade (удаляется университет - удаляются все студенты).
Для студента определим связь с университетом один к одному (т.к. для студента, только один университет).
Метод для вывода университета:
В конце добавляется еще сущность TACourse - курс (предмет) в университете.
Расставляются связи и правила в соответствии с логической моделью.
Создадим атрибут model типа String.
Студенту добавим связь - carRelation в Destination указываем TACar.
Указываем тип связи To One - один студент имеет одну машину.
В сущности TACar создаем ответную связь owner на студента и указываем связь To One. Машина имеет только одного владельца - студента.
Теперь определим тип правила удаления для TAStudent:
Nulify - это правило означает, что при удалении студента связь owner у соответствующей машины станет Null.
Если установить тип правила удаления - Cascade, то при удалении студента соответствующая машина тоже будет удалена.
Тип Deny означает, что если к примеру у студента есть 10 машин, то студент не удалится, пока не удалятся все его машины. Но иногда с ней происходят глюки (не рекомендуется использовать).
NoAction - ничего не происходит при удалении.
Нам для TAStudent по логике больше подходит Cascade. Если уходит (удаляется) студент, то сведения об его машине нам не нужны, т.е. TACar соответствующая тоже удаляется.
Для TACar выставляем правило для удаления - Nulify. Т.к. если удаляется машина, то студент может остаться.
Мы поменяли сущности и связи, пересоздадим класс для студента и машины. Для этого выделяем 2 сущности и нажимаем file-> new->file->core data->NSManagedObject subclass.
XCode автоматически сгенерирует файлы для классов в соответствии с настройками в модели.
Теперь у нас появилось 2 сущности TAStudent и TACar.
Чтобы вывести все объекты из базы за один запрос, необходимо создать базовую (родительскую сущность) и от нее унаследовать наши классы студента и машины.
Создаем родительскую сущность TABaseObject.
А для класса TAStudent и TACar выставляем родителя: Parent Entity - TABaseObject.
Теперь делаем методы для вывода всех объектов и удаления всех объектов:
- (NSArray *)arrayAllObject
{
NSFetchRequest *request = [[NSFetchRequest alloc]init];
NSEntityDescription *description = [NSEntityDescription entityForName:@"TABaseObject" inManagedObjectContext:self.managedObjectContext];
[request setEntity:description];
NSError *requestError = nil;
NSArray *arrayResult = [self.managedObjectContext executeFetchRequest:request error:&requestError];
if (requestError) {
NSLog(@"Request Error: %@", [requestError localizedDescription]);
}
return arrayResult;
}
- (void)deleteAllObjects
{
NSArray *arrayResult = [self arrayAllObject];
for (TABaseObject *object in arrayResult) {
[self.managedObjectContext deleteObject:object];
}
[self.managedObjectContext save:nil];
}
- (void)printAllObjects
{
NSArray *arrayResult = [self arrayAllObject];
for (TABaseObject *baseObject in arrayResult) {
NSLog(@"%@ ", baseObject);
}
}
Метод для создания студента и машины:
- (TAStudent *)addRandomStudent{
TAStudent *student = [NSEntityDescription insertNewObjectForEntityForName:@"TAStudent" inManagedObjectContext:self.managedObjectContext];
student.score = @(arc4random_uniform(201)/100.f +2.f);
student.dateBirth = [NSDate dateWithTimeIntervalSince1970:arc4random_uniform(20)*60*60*24*365];
student.lastName = lastNames[arc4random_uniform(50)];
student.firstName = firstNames[arc4random_uniform(50)];
return student;
}
- (TACar *)addRandomCar{
TACar *car = [NSEntityDescription insertNewObjectForEntityForName:@"TACar" inManagedObjectContext:self.managedObjectContext];
car.model = carModels[arc4random_uniform(5)];
return car;
}
TAStudent *student = [self addRandomStudent];
TACar *car = [self addRandomCar];
student.carRelation = car;
NSError *error;
if (![student.managedObjectContext save:&error]) {
NSLog(@"%@",[error localizedDescription]);
};
Для удобного вывода определим методы вывода для каждой сущности:
- (void)printStudent:(TAStudent*) studentForPrint
{
NSString *strReturn = [NSString stringWithFormat:@"TAStudent: %@ %@ = %@, Car: %@",
studentForPrint.firstName,
studentForPrint.lastName,
studentForPrint.score,
studentForPrint.carRelation.model? studentForPrint.carRelation.model: @""];
NSLog(@"%@", strReturn);
}
- (void)printCar:(TACar*) carForPrint
{
NSLog(@"TACar: Model %@. Owner: %@ %@",
carForPrint.model,
carForPrint.owner.firstName? carForPrint.owner.firstName: @"",
carForPrint.owner.lastName? carForPrint.owner.lastName: @"");
}
И общий метод вывода любого объекта:
- (void)printAllObjects
{
NSArray *arrayResult = [self arrayAllObject];
for (TABaseObject *baseObject in arrayResult) {
if ([baseObject isKindOfClass:[TAStudent class]]) {
[self printStudent:(TAStudent *)baseObject];
}
else if ([baseObject isKindOfClass:[TACar class]]){
[self printCar:(TACar *)baseObject];
}
else{
NSLog(@"Unknown type object: %@ ", baseObject);
}
}
}
Для проверки перед удалением определим метод в TAStudent.m для TAStudent и аналогичный для TACar:
- (BOOL)validateForDelete:(NSError **)error
{
NSLog(@"TAStudent ValidateForDelete");
return YES;
}
При удалении машины, метод вызвался только для машины.
Это происходит по тому, что для студента правило удаления стоит Cascade, а для машину Nulify.
Можно поместить этот метод в базовый класс TABaseObject.m
- (BOOL)validateForDelete:(NSError **)error
{
NSLog(@"%@ ValidateForDelete", NSStringFromClass([self class]));
return YES;
}
Проверим как работает связь один ко многим.
Для этого создадим новую сущность TAUniversity. Определим связь со студентами один ко многим (университет имеет много студентов) и правило удаление - Cascade (удаляется университет - удаляются все студенты).
Для студента определим связь с университетом один к одному (т.к. для студента, только один университет).
Метод для вывода университета:
- (void)printUniversity:(TAUniversity*) universityForPrint
{
NSString *strReturn = [NSString stringWithFormat:@"TAUniversity: %@. Students: ",
universityForPrint.nameUniversity];
for (TAStudent *student in universityForPrint.relationStudent) {
strReturn = [NSString stringWithFormat:@"%@ %@", strReturn, student.lastName];
}
NSLog(@"%@", strReturn);
}
Для создания университета и добавления в него студента:
TAUniversity *university;
NSFetchRequest *request = [[NSFetchRequest alloc]init];
NSEntityDescription *description = [NSEntityDescription entityForName:@"TAUniversity" inManagedObjectContext:self.managedObjectContext];
[request setEntity:description];
NSError *requestError = nil;
NSArray *arrayResult = [self.managedObjectContext executeFetchRequest:request error:&requestError];
if (arrayResult.count > 0) {
university = [arrayResult firstObject];
}
else{
university = [NSEntityDescription insertNewObjectForEntityForName:@"TAUniversity" inManagedObjectContext:self.managedObjectContext];
university.nameUniversity = @"NSTU";
}
TAStudent *student = [self addRandomStudent];
TACar *car = [self addRandomCar];
student.carRelation = car;
[university addRelationStudentObject:student];
NSError *error;
if (![student.managedObjectContext save:&error]) {
NSLog(@"%@",[error localizedDescription]);
};
В конце добавляется еще сущность TACourse - курс (предмет) в университете.
Расставляются связи и правила в соответствии с логической моделью.
Домашнее задание в завершающем 44 -м уроке по CoreData.
Merkur Solingen Razor Metal Shave - Stainless Steel - Titanium
ОтветитьУдалитьMerkur Solingen Razor Metal Shave head titanium tennis racket - Stainless Steel - Titsanium-Artey Metal Shave - titanium dental Stainless Steel - Titsanium-Artey - Stainless Steel - Titsanium-Artey - Stainless Steel - ford ecosport titanium Titsanium-Artey 2021 ford escape titanium hybrid - Stainless Steel titanium athletics - Titsanium