Ошибка в iOS SDK или мое неправильное представление о взаимосвязи наследования сущности? - PullRequest
0 голосов
/ 26 августа 2011

Я столкнулся с этой проблемой несколько дней назад ( ссылка ).Кратко расскажу об этом с помощью простого примера.У меня есть компания Company, в которую входят многие сотрудники Entity и один CEO (которая унаследована от сотрудника).

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

В шоке от этого события я начинаю искать объяснения вApple Doc, я вижу две связанные статьи Выборка и наследование сущности , в которых говорится

Если вы определяете иерархию наследования сущности (см. «Наследование сущности»), когда вы указываете супер-В качестве объекта для запроса выборки запрос возвращает все совпадающие экземпляры супер-объекта и дочерних объектов.

и Основы отношений , говорящие

Отношение определяет сущность или родительскую сущность объектов в месте назначения.Это может быть то же самое, что и сущность в источнике (рефлексивная связь).Отношения не должны быть однородными.Если у объекта «Сотрудник» есть два дочерних объекта, например «Менеджер» и «Flunky», то сотрудники данного отдела могут состоять из «Сотрудников» (при условии, что «Сотрудник» не является абстрактным объектом), «Менеджеров», «Операторов» или любой их комбинации.

Это нормальное поведение?если да, я могу вернуться, чтобы изменить мой вопрос ( здесь ) с душевным спокойствием.И было бы замечательно, если бы кто-то мог указать мне на документ, где эта ситуация объясняется более подробно.

Спасибо

Обновлена ​​тема и добавлен репро шаг Теперь я 'Я думаю, что это может быть какая-то ошибка SDK.Вот мой шаг воспроизведения Сделайте 3 сущности

Family 
- int generation
- parents as to-may relation to Parent and family as inverse
- child as to-one relation to Child and family as inverse
Parent
- String name
- family to-one relation to Family
Child : Parent

Вот мой код

Family *fam;

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Family" inManagedObjectContext:self.managedObjectContext];

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];

NSArray *meters = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];

if ([meters count] > 0) {
    NSLog(@"found");
    fam = [meters lastObject];
    fam.generation = [NSNumber numberWithInt:[fam.generation intValue] + 1];
} else {
    NSLog(@"new");
    fam = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:self.managedObjectContext];
    fam.generation = [NSNumber numberWithInt:1];
    [self saveContext];
};
NSLog(@"There are %d paren", [fam.parents count]);
for (Parent *p in fam.parents) {
    NSLog(@"name : %@", p.name);
}
Child *child;
if (!fam.child) {
    child = [NSEntityDescription insertNewObjectForEntityForName:
             [[NSEntityDescription entityForName:@"Child" inManagedObjectContext:self.managedObjectContext] name]
                                          inManagedObjectContext:self.managedObjectContext];
    fam.child = child;
}
fam.child.name = [NSString stringWithFormat:@"child number %d", [fam.generation intValue]];
NSLog(@"There are %d parent after adding one child", [fam.parents count]);

Parent *parent = [NSEntityDescription insertNewObjectForEntityForName:
                  [[NSEntityDescription entityForName:@"Parent" inManagedObjectContext:self.managedObjectContext] name]
                                               inManagedObjectContext:self.managedObjectContext];
parent.name = [NSString stringWithFormat:@"parent number %d", [fam.generation intValue]];
[fam addParentsObject:parent];

NSLog(@"There are  %d parent after add parent", [fam.parents count]);
for (Parent *p in fam.parents) {
    NSLog(@"name : %@", p.name);
}

[self saveContext];

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

2011-08-27 19:06:28.271 child[2015:207] new
2011-08-27 19:06:28.276 child[2015:207] There are 0 paren
2011-08-27 19:06:28.278 child[2015:207] There are 0 parent after adding one child
2011-08-27 19:06:28.279 child[2015:207] There are  1 parent after add parent
2011-08-27 19:06:28.280 child[2015:207] name : parent number 1

, что я и ожидал, затем я снова запускаю приложение, и это то, что происходит странно

2011-08-27 19:08:12.383 child[2035:207] found
2011-08-27 19:08:12.386 child[2035:207] There are 2 paren
2011-08-27 19:08:12.387 child[2035:207] name : parent number 1
2011-08-27 19:08:12.388 child[2035:207] name : child number 1
2011-08-27 19:08:12.389 child[2035:207] There are 2 parent after adding one child
2011-08-27 19:08:12.390 child[2035:207] There are  3 parent after add parent
2011-08-27 19:08:12.390 child[2035:207] name : parent number 1
2011-08-27 19:08:12.391 child[2035:207] name : parent number 2
2011-08-27 19:08:12.391 child[2035:207] name : child number 2

Без причины дочерняя сущностьвходит в собственность fam.parents.

1 Ответ

0 голосов
/ 27 августа 2011

Я не думаю, что первое, что вы цитировали, это ваша проблема. Ссылка на company.employees не является запросом на выборку.

Я подозреваю, что это может быть связано с обратными отношениями. Есть ли у вас партнерская компания на сотрудника, что противоположно Company.employees?

Затем, когда вы назначаете генерального директора в такую ​​компанию:

ceo.company = company;

Тогда за кулисами Core Data говорит, что генеральный директор - сотрудник. Когда вы назначаете компанию Сотруднику, присваивайте обратную связь. Назначьте Сотрудника сотрудникам компании. Создает эффект следующего кода автоматически:

[company addEmployeesObject:ceo];

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

EDIT:

Поведение во втором прогоне вашего примера «родитель-ребенок» - то, чего я ожидал.

Вы назначаете

fam.child = child

Обратное отношение Family.child - Child.family, поэтому Базовые данные генерируют присваивание

child.family = fam

Ребенок наследует от Родителя. Обратное отношение Parent.family - Family.parent, поэтому обратное отношение Child.family - также Family.parent. Поэтому Core Data генерирует вставку

[fam addParentsObject:child]

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

Возможно, вы можете назвать это ошибкой, но в любом случае ошибочное поведение на самом деле то, что вы хотите. Чего вы не хотите, так это того, что происходит во втором запуске, что на самом деле является «правильным» поведением. На самом деле, поведение на самом деле не определено, потому что вы создали несогласованную модель данных. Фактически вы сказали

Обратное значение A.b - B.a

Обратное значение B.a - A.c

Инверсии на самом деле не инверсии. Я думаю, вы найдете предупреждение об этом при сборке.

Ладно, как решить исходную проблему?

Мое первое предложение - вы не заставляете генерального директора наследовать от сотрудника. Но если у вас есть причины, по которым вы хотите это сделать, то вот как это сделать.

Базовые данные требуют, чтобы вы определили обратные и чтобы обратные правила следовали правилам базовых данных. Если вы не хотите следовать правилам Core Data, тогда определяйте обратные правила в соответствии с правилами Core Data, но не используйте их. Определите вашу модель данных следующим образом:

Company
  employees: (to-many) Employee - inverse isEmployeeOf
  ceo: (to-one) CEO - inverse isCEOOf
  // unused
  people: (to-many) Employee - inverse company

Employee
  company: (to-one) Company - inverse people
  // unused
  isEmployeeOf: (to-one) Company - inverse employees

CEO : Employee
  // unused
  isCEOOf: (to-one) Company - inverse ceo

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

[myCompany addEmployeesObject:mrEmployee];
mrEmployee.company = myCompany; // not automatic, because not official inverse
myCompany.ceo = mrCEO;
mrCEO.company = myCompany;

Тогда они будут иметь следующие отношения:

myCompany
  employees - {mrEmployee}
  ceo - mrCEO
  people - {mrEmployee, mrCEO}

mrEmployee
  company - myCompany
  isEmployeeOf - myCompany

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