Entity-Framework: создание отношений «многие ко многим» - PullRequest
0 голосов
/ 02 мая 2018

Мы используем подход «DB-First» для приложения, поскольку база данных совместно используется различными приложениями, поэтому она должна быть «главной». (MySQL)

У нас есть 3 простые таблицы, отвечающие за Role-To-Permission Назначение, например:

enter image description here

Visual-Studio Model Designer (после построения модели из базы данных) прекрасно замечает это как отношение «многие ко многим», даже не генерируя объект «Role_to_permission», так как никаких дополнительных атрибутов на назначение)

enter image description here

До сих пор мы создавали те записи в базе данных, которые приводят к ожидаемому результату в приложении. (Доступ к сопоставлениям)

В настоящее время мы работаем над интерфейсом, позволяющим назначать «Права» для «Роли». И тут я немного застрял:

  • Если такое отношение имеет другой атрибут (например, required или date), EMF создает собственный объект для отношения - предположим, Permission_To_Role.

тогда я могу "легко" создать отношение со следующим кодом:

using (MyDb db = new MyDB()){
   Permission_To_Role ptr = new Permission_To_Role();
   ptr.PermissionId = 5;
   ptr.RoleId = 8;
   ptr.CreationDate = DateTime.Now();

   db.Permission_To_Role.Add(ptr);
   db.SaveChanges();
}

Как бы то ни было - в этом случае - у нас нет дополнительных атрибутов в отображении, поэтому дополнительный класс исключен EF Framework.

Я сейчас очень стараюсь создать отношения, но безуспешно:

using (MyDB db = new MyDB())
{
    //Get ids.
    long permissionId = 2;
    long roleID = 5;

    Permission p = db.Permission.Find(permissionId);
    Role r = db.Role.Find(roleID);

    r.Permissions.Add(p);

    db.SaveChanges();
}

Это всегда приводит к исключению, и я не могу понять, почему (идентификаторы существуют и правильны) ...

Исключение db.SaveChanges():

Исключение типа «System.Data.Entity.Infrastructure.DbUpdateException» произошло в EntityFramework.dll, но не был обработан в коде пользователя

Дополнительная информация: при сохранении сущностей произошла ошибка не выставляйте свойства внешнего ключа для их отношений. Свойство EntityEntries вернет значение NULL, поскольку один объект не может быть идентифицированным как источник исключения. Обработка исключений в то время как сохранение может быть сделано проще, выставляя свойства внешнего ключа в ваши типы сущностей. Подробности смотрите в InnerException.

Внутреннее исключение:

Произошла ошибка при обновлении записей. Смотрите внутреннее исключение для деталей.

Внутреннее Внутреннее Исключение:

В вашем синтаксисе SQL есть ошибка; проверьте руководство, которое соответствует вашей версии сервера MySQL для правильного использования синтаксиса рядом '(ВЫБРАТЬ Permission_to_Role. PermissionId, Permission_to_Role. RoleId ОТ 'в строке 1

Идеи


Обновление:

SHOW CREATE TABLE Permission_to_Role;

выход:

CREATE TABLE `Permission_to_Role` (
  `PermissionId` bigint(19) NOT NULL,
  `RoleId` bigint(19) NOT NULL,
  UNIQUE KEY `Permission_to_Role_unique` (`PermissionId`,`RoleId`),
  KEY `Permission_Mapping_idx` (`PermissionId`),
  KEY `Role_Mapping_idx` (`RoleId`),
  CONSTRAINT `Permission_Mapping` FOREIGN KEY (`PermissionId`) REFERENCES `permission` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION,
  CONSTRAINT `Role_Mapping` FOREIGN KEY (`RoleId`) REFERENCES `role` (`Id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Update2:

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

INSERT INTO 
  (SELECT 
    Permission_to_Role.PermissionId,
    Permission_to_Role.RoleId  
   FROM 
     Permission_to_Role AS Permission_to_Role
  )
  ( PermissionId, RoleId) VALUES ( 2, 1)

Фактический запрос должен быть:

INSERT INTO 
  Permission_To_Role
  ( PermissionId, RoleId) VALUES ( 2, 1)

Итак, я думаю, это выглядит как "ошибка"? Как уже упоминалось выше:

Как бы то ни было - в этом случае - у нас нет никакого дополнительного атрибута в отображении, поэтому дополнительный класс исключен EF Framework.

промежуточного звена Permission_To_Role нет, следовательно, EF пытается заменить это имя таблицы на запрос

  SELECT 
    Permission_to_Role.PermissionId,
    Permission_to_Role.RoleId  
   FROM 
     Permission_to_Role AS Permission_to_Role

ДАЖЕ при вставках ... (Может быть, это работает для MsSQL и является плохой реализацией для MySQL Connector?)

Ответы [ 2 ]

0 голосов
/ 03 мая 2018

Я немного устал сейчас, но наконец-то получил его на работу.

Я не уверен на 100%, чтобы обрисовать реальную проблему, потому что я многое изменил - но следующие «выводы» являются своего рода вехами при решении этой проблемы:

Во-первых,

Я попытался добавить больше столбцов, как упомянуто выше, но это не сработало. Это привело к тому, что Mapping-Table была представлена ​​как сущность, но вставка показала ту же проблему. (Вместо имени таблицы вставить запрос, содержащий проводной оператор SELECT)

Во-вторых,

Я отметил, что сгенерированная таблица сопоставления (в EM-Designer) учитывает ВСЕ столбцы для первичного ключа , , в то время как я проектировал таблицу без какого-либо (составного) первичного ключа в MySQL-Designer (для всех столбцов был установлен только уникальный ключ):

enter image description here

В-третьих,

Я был как f *** y ** - и добавил суррогатный первичный ключевой столбец в таблицу сопоставления (в конструкторе базы данных) ...

enter image description here

и снимите флажок любого членства первичного ключа в EF-Designer для любого оставшегося столбца:

enter image description here

И угадайте что? Это работает :-)

using (MyDb db = new MyDB()){
    Permission_to_Role ptr = new Permission_to_Role();
    ptr.PermissionId = permissionId;
    ptr.RoleId = r.Id;
    ptr.GrantedById = u.Id;
    ptr.GrantedAt = DateTime.Now;

    db.Permission_to_Role.Add(ptr);
    db.SaveChanges();
}

Итак, осталось сказать три вещи:

  • Во-первых (я заметил это довольно давно) - При синхронизации вашей Модели с базой данных - есть изменения, которые не регистрируются ... И вам будет трудно разобраться с этим. Это могут быть только «индексы», но также могут быть такие вещи, как «ограничения внешнего ключа» или даже «настройки первичного ключа». (Рассмотрим Hibernate (Java) в качестве мастера правила 80/20: Hibernate делает 80% - Поиск последних 20% зависит от пользователя!)
  • Второе: эта проблема может быть комбинацией специальной схемы базы данных, опирающейся на сторонние фреймворки и ожидающей, что все будет красиво и чисто автоматически ... Только доверяйте "себе"!
  • В-третьих: всегда используйте суррогатный первичный ключ для каждой таблицы. Это совсем не больно, но позволяет избежать всех хлопот с первичными первичными ключами. (Которые вы можете настроить как уникальные ключи в любом случае)
0 голосов
/ 03 мая 2018

Мне бы очень хотелось выяснить «причину» этой проблемы, но сейчас я добавил еще один столбец grantedById (ссылающийся на user.id) в эту таблицу отношений.

enter image description here

Итак, это вызвало создание промежуточной сущности Permission_To_Role в модели, и заставило меня поверить, что она будет работать сейчас! (Потому что это делалось сотни раз, вот так:)

 using (MyDb db = new MyDB()){
   Permission_To_Role ptr = new Permission_To_Role();
   ptr.PermissionId = 5;
   ptr.RoleId = 8;
   ptr.GrantedById = Session.CurrentUser.Id;

   db.Permission_To_Role.Add(ptr);
   db.SaveChanges();
}

Но должна быть возможность делать вставки базы данных для Many-To-Many-Mappings ТОЛЬКО с 2 Foreign-Key-Constraint Columns, не так ли?

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