Атрибут ForeignKeyAttribute ядра Entity Framework с обеих сторон

#c# #.net #database #entity-framework #entity-framework-core

#c# #.net #База данных #entity-framework #entity-framework-core

Вопрос:

У меня есть приложение с ядром Entity Framework с разными объектами в моем контексте, но есть два из них, для которых требуется отношение один к нулю или один. Мой способ сделать это и обеспечить проверку состоял в том, чтобы сделать что-то вроде следующего:

 public class PurchasedPackage
{
    public int Id { get; set; }

    ...

    [ForeignKey(nameof(PurchasedPackageModifier))]
    public int? PurchasedPackageModifierId { get; set; }

    public virtual PurchasedPackageModifier PurchasedPackageModifier { get; set; }
}
 

И

 public class PurchasedPackageModifier
{
    public int Id { get; set; }

    ...

    [Required]
    [ForeignKey(nameof(PurchasedPackage))]
    public int PurchasedPackageId { get; set; }

    public virtual PurchasedPackage PurchasedPackage { get; set; }

    ...
}
 

Где PurchasedPackage требуется и PurchasedPackageModifier является необязательным. Указывая ForeignKey атрибут с обеих сторон, я пытаюсь обеспечить целостность данных при сохранении в обеих таблицах, чтобы никто не создавал a PurchasedPackage с несуществующим PurchasedPackageModifier и наоборот.

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

 'PurchasedPackage.PurchasedPackageModifier' and 'PurchasedPackageModifier.PurchasedPackage' were separated into two relationships as ForeignKeyAttribute was specified on properties 'PurchasedPackageModifierId' and 'PurchasedPackageId' on both sides.
 

И

 'PurchasedPackageModifier.PurchasedPackage' and 'PurchasedPackage.PurchasedPackageModifier' were separated into two relationships as ForeignKeyAttribute was specified on properties 'PurchasedPackageId' and 'PurchasedPackageModifierId' on both sides.
 

Мой вопрос: правильно ли я это делаю и должен ли я игнорировать эти предупреждения в данном конкретном случае или есть лучший способ добиться такого же поведения проверки / целостности?

Комментарии:

1. Where PurchasedPackage is required and PurchasedPackageModifier is optional. By specifying ForeignKey attribute on both sides I'm trying to ensure data integrity across saves to both tables so nobody creates a PurchasedPackage with a non-existent PurchasedPackageModifier and vice versa. Это немного противоречит мне, поэтому, если вы не можете создать одно без другого, тогда ничего не является необязательным, или я что-то упускаю?

2. @cantSleepNow с помощью MSSQL создаются 2 FK, по одному для каждой таблицы. Что касается требуемого / необязательного вопроса — PurchasedPackage может иметь нулевой или один PurchasedPackageModifier , который, в свою очередь, не может существовать без PurchasedPackage . Можно создать / обновить PurchasedPackage без модификатора, но если модификатор указан, его следует проверить на целостность. Модификатор PurchasedPackageModifier всегда должен содержать PurchasedPackage, к которому он применяется.

3. Спасибо за разъяснение, я соответствующим образом отредактирую ответ

Ответ №1:

Этот вопрос о предупреждениях закрыт в апреле 2018 года. Теперь я попробовал ваши два класса с mysql (библиотека pomelo), и действительно, я получаю один FK. Поэтому, если это приемлемо для вас, вы можете игнорировать предупреждения (процитировать одного из разработчиков по этой ссылке на github)

Если вам действительно нужно «отношение один к нулю или один», то я бы сделал это следующим образом:

  • PurchasedPackage не имеет FK to PurchasedPackageModifier , под этим я подразумеваю удаление обоих int? PurchasedPackageModifierId и свойства навигации urchasedPackageModifier PurchasedPackageModifier — это охватывает часть 1-0, где запись в PurchasedPackage может существовать без соответствующего PurchasedPackageModifier существующего
  • PurchasedPackageModifier имеет столбец PurchasedPackageId , который является FK to PurchasedPackage , а также уникальный индекс — это охватывает часть 1-1, где

Комментарии:

1. Я действительно хочу, чтобы один-ноль-или-один, проблема в том, что если я пропущу FK для PurchasedPackage, тогда можно сохранить объект PurchasedPackage с помощью PurchasedPackage. PurchasedPackageModifierId устанавливается в любое недопустимое значение, которое не соответствует ни одному существующему идентификатору в таблице PurchasedPackageModifier

2. отредактируйте ответ и после этого комментария. Первоначально, удаляя FK, я имел в виду, что вы удаляете как свойство int, так и свойство навигации.

3. Правильно ли я предполагаю, что мои 2 варианта либо имеют 2 FK, либо полностью удаляют доступ к PurchasedPackageModifier для PurchasedPackage?

4. Я не знаю, являются ли они единственными 2 🙂 Но 2 FKS в этом случае кажется немного странным. Может быть, посмотрите на варианты использования, описанные в моей идее: 1- У вас может быть a PurchasedPacakge , которого нет PurchasedPackageModifier , и вы можете запрашивать такие записи. 2- Если у вас есть PurchasedPackageModifier соответствующие PurchasedPacakge записи ahs, которые должны существовать (благодаря FK), и у него может быть только один из них (благодаря UniqueIDX), вы также можете запросить все PP, у которых есть PPM.

5. Таким образом, вы не удаляете доступ, потому что таким образом доступ не требуется, если вы просто PP JOIN PPM, вы получите все PPS, у которых есть PPM, если вы делаете PP LEFT JOIN PPM, ГДЕ INSULL (PPM) (очевидно, псевдокод), вы можете получить все PPS, у которых нет PPM. Это все, что вам нужно. Поэтому ищите существование PPM, используя две таблицы вместо одной