Как я могу заставить Entity Framework Code First принимать типы внешних ключей «не в фазе», таблица БД против сущности NET? - PullRequest
0 голосов
/ 31 января 2020

У меня есть унаследованный проект Code First Entity Framework, в котором объекты в C# вышли из фазы с базой данных. Когда я пытаюсь создать отношение «родитель-ребенок-1-к-1» с существующей таблицей, EF не может создать действительный SQL для установления отношения внешнего ключа (FK).

В этом случае родительская сущность называется ApplicantRegistration. Мне нужно связать это, один к одному, с сущностью User, чтобы представлять CaseManager, который принадлежит каждому заявителю. (Сущность User используется в качестве дочернего отношения во многих других родительских сущностях.)

Достаточно прост на первый взгляд. Я добавил следующее к ApplicantRegistration ...

public User CaseManager { get; set; }

Но у User есть идентификатор, который говорит это ...

    public class User
    {
        [Key]
        public int UserId { get; set; }
    // ...

... и, в MySQL, таблица Users , относящаяся к этому объекту, имеет это ...

  `UserId` bigint(15) NOT NULL AUTO_INCREMENT,

>>> С bigint и int не вешайте, я получаю сообщение об ошибке, когда EF пытается создать внешний ключ. <<< </strong>

Столбец int (EF называет его CaseManager_UserId) добавляется в таблицу ApplicantRegistrations отлично, но создание FK не работает.

Вот автоматически сгенерированный EF SQL:

ALTER TABLE ApplicantRegistrations
ADD COLUMN CaseManager_UserId int NULL
CREATE INDEX IX_ApplicantRegistrations_CaseManager_UserId ON ApplicantRegistrations (CaseManager_UserId)
ALTER TABLE ApplicantRegistrations
  ADD CONSTRAINT FK_ApplicantRegistrations_Users_CaseManager_UserId FOREIGN KEY (CaseManager_UserId) REFERENCES Users (UserId)
  ON DELETE NO ACTION ON UPDATE NO ACTION

ADD CONSTRAINT FK_ApplicantRegistrations_Users_CaseManager_UserId FOREIGN KEY (CaseManager_UserId) не будет работать, поскольку int и bigint не совпадают.


Рассматриваемые параметры

1. Поменяйте int на long в User в C#

Я изначально начал переключаться с int на UserId на User сущности на long (это в C#) чтобы посмотреть, совпадет ли это с bigint в сгенерированном коде EF, но это, на самом деле, быстро превратилось в беспорядок. После того как я поменял public int UserId { get; set; } на public long UserId { get; set; } и исправил последствия изменения типа для связанных сущностей и кода, я получил ряд ошибок, таких как следующие при попытке Add-Migration:

System.Data.Entity.ModelConfiguration. так же, как соответствующие типы свойств в главной роли. Тип свойства «WorksiteAdministratorUserId» для сущности «ProgramWorksite» не соответствует типу свойства «UserId» для сущности «User» в ссылочном ограничении «ProgramWorksite_WorksiteAdministratorUser».

Разумеется, это имеет смысл - теперь я должен изменить все остальные места User используется как дочерние отношения. (Их 33, и мне кажется, что должен быть более простой способ, поэтому я отложил int до long в User сейчас в надежде найти что-то лучшее, но я, вероятно, вернусь после публикации.)

2. Поменяйте bigint на int в Users в MySQL

Я также пытался поменяться с bigint на int в MySQL, но для этого потребовалось бы сбросить и заменить тонны ФК отношения с UserId в базе данных, что является возможным решением, но не очень весело. Я думаю, что исправить это в C# было бы проще - при условии, что long отобразится в bigint, что я точно не знаю. ( ОБНОВЛЕНИЕ: long соответствует bigint(15), по крайней мере, в этой системе.)

3. Попробуйте аннотировать столбец в ApplicantRegistration

Я думал, что смогу использовать переопределение Column только для целей EF, как это, внутри Applicant ...

Column("CaseManagerId", TypeName = "bigint(15)")]
public User CaseManager { get; set; }

К сожалению, это дало ту же ошибку, что и раньше - и оно не использовало имя CaseManagerId, которое я использовал, вместо того, чтобы вернуться по умолчанию к CaseManager_UserId. Так что, в лучшем случае, я сделал неправильную аннотацию.

Маршрут аннотации действительно мой любимый, если есть способ заставить его работать - если бы он мог заставить EF игнорировать то, что в сущности User UserId определение достаточно длинное, чтобы создать отношение FK и завершить миграцию, я золотой.


Какой самый эффективный способ вставить это новое отношение, если я не хочу отбрасывать код EF Во-первых?

1 Ответ

0 голосов
/ 04 февраля 2020

Хорошо, я надеюсь, что кто-нибудь вернется и скажет мне, что есть лучший способ, и я могу переместить чек, но сейчас, вот что я делаю ...


Так как все, что действительно делает Add-Migration, - это автоматическое генерирование некоторого C#, вы можете взять этот автоматически сгенерированный код и взломать его в соответствии с вашим вариантом использования - в этом случае, игнорируя, что объект использует int, а база данных использует bigint / long.

Взлом кода миграции перед запуском Update-Database ничего не нарушает. То есть ничего не проверяется, чтобы убедиться, что ваши миграции для вашего хранилища данных соответствуют определениям сущностей (в коде) до запуска миграции C#.

В моем случае это означает, что мне нужно изменить это Up метод из того, что было автоматически сгенерированным кодом ...

        public override void Up()
        {
            AddColumn("dbo.ApplicantRegistrations", "CaseManager_UserId", c => c.Int());

            CreateIndex("dbo.ApplicantRegistrations", "CaseManager_UserId");
            AddForeignKey("dbo.ApplicantRegistrations", "CaseManager_UserId", "dbo.Users", "UserId");
        }

... к этому ...

        public override void Up()
        {
            AddColumn("dbo.ApplicantRegistrations",
                "CaseManager_UserId", c => c.Long()); // <<< This from Int to Long

            CreateIndex("dbo.ApplicantRegistrations", "CaseManager_UserId");
            AddForeignKey("dbo.ApplicantRegistrations", "CaseManager_UserId", "dbo.Users", "UserId");
        }

Это вонючий .

Как отмечает @ Ctznkane525 , поскольку в этом приложении мы вряд ли найдем пользователей 2147483647, bigint излишне, и разработчики этой системы (возможно, включая меня) должны в конечном итоге выбрать вариант # 2 из OP, и исправьте поврежденную схему в какой-то момент.

Таким образом, быстрое решение (и ответ на этот конкретный c вопрос) состоит в том, чтобы EF игнорировал синфазную сущность и Схема путем взлома файла миграции / C# code.

Однако необходимо сделать так, чтобы схема базы данных и код объекта соответствовали друг другу. Может быть, вы bcp извлекаете данные, массируете базу данных с помощью int из bigint и воссоздаете схему, если производство может выдержать некоторое время простоя, или, возможно, вы кусаете пулю и придерживаетесь безумно большого bigint s в вашей схеме и закончил sh выполнение # 1 из вопроса, чтобы код EF соответствовал и перезапустил вашу первоначальную миграцию. Но пока это взломать.

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