1

Я использую сначала код EF. Мне нужно изменить тип данных первичного ключа одной таблицы в нашей производственной базе данных.Изменение типа данных первичного ключа в производственной базе данных

public class Course 
{ 
    [Key] 
    public Guid Id {get; set;} //This needs to be changed to int 

    public string Name {get;set;} 

    public virtual ICollection<Group> Groups {get;set;} 
} 

public class Group 
{ 
    [Key] 
    public Guid Id {get; set;} 

    public string Name {get;set;} 

    public virtual ICollection<Course> Courses{get;set;} 
} 

Как выше многие-многие отношения, EF создала таблицу соединения GroupCourses автоматически с ПК & FK в качестве как Group_Id и Course_Id. Это нормально до сих пор.

Теперь мне нужно изменить первичный ключ Course на int от Guid.

Я изменил тип данных с Guid на int и успешно создал новую миграцию. Но когда я пытаюсь запустить команду update-database, я получаю ниже ошибки.

Операнд типа столкновение: UniqueIdentifier несовместима с междунар в запросе

Я не знаю, как исправить ошибку выше.

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

Может кто-нибудь скажет мне, есть ли лучший способ достичь этого, не теряя данные?

ПРИМЕЧАНИЕ: Я прошел через другие связанные с СО сообщения и другие интернет-форумы, но не повезло.

+0

Не удалось выполнить переход, чтобы добавить CourseTemp, который возвращает все данные из старой таблицы курса в Temp с помощью метода 'Seed()'? Затем вы можете выполнить другую миграцию, чтобы удалить исходный курс и переименовать класс/таблицу CoureseTemp? – Bwolfing

ответ

1

Вы получаете сообщение об ошибке типа коллизий, поскольку генерируемый миграция пытается сделать непосредственно ALTER COLUMN на пораженные колоннах, чтобы изменить тип от Guid к integer, и это не представляется возможным, потому что Guid значения не могут быть неявно преобразованы в integer значения.

Вы должны вручную изменить свою миграцию. Удалите линии AlterColumn. Чтобы перенести существующие идентификаторы курса без потери данных, вы можете временно переименовать существующие столбцы Guid (добавив суффикс _Old), создать новые столбцы с правильным новым именем и типом, заполнить содержимое в таблице отношений с правильными значениями, используя UPDATE с SELECT, и, наконец, удалить старые колонки:

public override void Up() 
{ 
    DropForeignKey("dbo.GroupCourses", "Course_Id", "dbo.Courses"); 
    DropIndex("dbo.GroupCourses", new[] { "Course_Id" }); 
    DropPrimaryKey("dbo.Courses"); 
    DropPrimaryKey("dbo.GroupCourses"); 

    //Removed: AlterColumn("dbo.Courses", "Id", c => c.Int(nullable: false, identity: true)); 
    RenameColumn("dbo.Courses", "Id", "Id_Old"); //Added 
    AddColumn("dbo.Courses", "Id", c => c.Int(nullable: false, identity: true)); //Added 

    //Removed: AlterColumn("dbo.GroupCourses", "Course_Id", c => c.Int(nullable: false)); 
    RenameColumn("dbo.GroupCourses", "Course_Id", "Course_Id_Old"); //Added 
    AddColumn("dbo.GroupCourses", "Course_Id", c => c.Int(nullable: false)); //Added 
    Sql(@"UPDATE gc SET gc.Course_Id = c.Id " 
      + "FROM dbo.GroupCourses as gc " 
      + "INNER JOIN dbo.Courses as c ON gc.Course_Id_Old = c.id_Old"); //Added 

    DropColumn("dbo.GroupCourses", "Course_Id_Old"); //Added 
    DropColumn("dbo.Courses", "Id_Old"); //Added 

    AddPrimaryKey("dbo.Courses", "Id"); 
    AddPrimaryKey("dbo.GroupCourses", new[] { "Group_Id", "Course_Id" }); 
    CreateIndex("dbo.GroupCourses", "Course_Id"); 
    AddForeignKey("dbo.GroupCourses", "Course_Id", "dbo.Courses", "Id", cascadeDelete: true); 
} 

Я пометил в коде строки, я изменил с комментариями //Added и //Removed. Остальная часть кода является исходной в миграции, сгенерированной с Add-Migration после изменения типа свойства на int в модели.

Вы должны заполнить только значениями в столбце таблицы взаимосвязей. UPDATE. Значения в столбце Courses.Id будут автоматически генерироваться, так как это столбец identity.

Вы также должны выяснить метод Down() и реализовать обратный процесс или оставить его как есть, если вы действительно никогда не собираетесь понижать базу данных до предыдущей миграции.

Вы также можете сделать это, разделив код между миграцией и сеялкой. Это было бы более правильно концептуально, поскольку вы должны использовать миграции для модификаций схемы и сеялки для модификации данных. Но я думаю, что это проще, и вам нужна только одна миграция, в то время как при использовании сеялки вам потребуются две миграции: одна со всем кодом, включенным выше, кроме UPDATE и предложения, которые бросают столбцы _Old, а другой с падением столбцов _Old. Часть UPDATE будет реализована в сеялке.

Предупреждение: код SQL, включенный в предложение UPDATE, работает с Sql Server, но может не работать с другими двигателями базы данных. Это еще один недостаток использования миграции вместо сеялки.

+0

Очень подробный ответ. Спасибо :-) – Venky

+0

Добро пожаловать! – Diana

Смежные вопросы