2016-03-15 6 views
7

私はEFコードファーストアプローチを使用していて、Idフィールドを​​に変更したいのですが、以下のエラーを過ぎているとは思われません。EFの移行でint ID列をGuidに変更するにはどうすればよいですか?

これが私の最初の移行である:

public partial class CreateDownloadToken : DbMigration 
{ 
    public override void Up() 
    { 
     CreateTable(
      "dbo.DownloadTokens", 
      c => new 
      { 
       Id = c.Int(nullable: false, identity: true), 
       FileId = c.Int(), 
       UserId = c.String(nullable: false, maxLength: 128), 
       ValidUntil = c.DateTime(nullable: false), 
      }) 
      .PrimaryKey(t => t.Id) 
      .ForeignKey("dbo.Files", t => t.FileId) 
      .ForeignKey("dbo.Users", t => t.UserId, cascadeDelete: true) 
      .Index(t => t.FileId) 
      .Index(t => t.UserId); 

    } 

    public override void Down() 
    { 
     DropForeignKey("dbo.DownloadTokens", "UserId", "dbo.Users"); 
     DropForeignKey("dbo.DownloadTokens", "FileId", "dbo.Files"); 
     DropIndex("dbo.DownloadTokens", new[] { "UserId" }); 
     DropIndex("dbo.DownloadTokens", new[] { "FileId" }); 
     DropTable("dbo.DownloadTokens"); 
    } 
} 

後、私は私のモデルファイルに変更して、私は私が私のId列がGUIDする必要があることに気づい:

public class DownloadToken 
{ 
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Computed)] 
    public Guid Id { get; set; } 

    public int? FileId { get; set; } 

    [ForeignKey("FileId")] 
    public virtual File File { get; set; } 

    [Required] 
    public string UserId { get; set; } 

    [ForeignKey("UserId")] 
    public virtual User User { get; set; } 

    [Required] 
    public DateTime ValidUntil { get; set; } 
} 

Add-Migration ChangeDownloadTokenIdToGuidを実行していることは、このファイルを生成します:

public partial class ChangeDownloadTokenIdToGuid : DbMigration 
{ 
    public override void Up() 
    { 
     DropPrimaryKey("dbo.DownloadTokens"); 
     AlterColumn("dbo.DownloadTokens", "Id", c => c.Guid(nullable: false)); 
     AddPrimaryKey("dbo.DownloadTokens", "Id"); 
    } 

    public override void Down() 
    { 
     DropPrimaryKey("dbo.DownloadTokens"); 
     AlterColumn("dbo.DownloadTokens", "Id", c => c.Int(nullable: false, identity: true)); 
     AddPrimaryKey("dbo.DownloadTokens", "Id"); 
    } 
} 

でこのファイルを実行するはこのエラーの原因となります:

Identity column 'Id' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, and constrained to be nonnullable. 

これはどうして起こっているのでしょうか?

答えて

13

(正確にはAlterColumn方法を実行してみてください)Guid型にId列の前のint種類を変換することは不可能であるため、それが発生しました。また、新しいタイプのId列は、int、bigint、smallint、tinyint、または小数点以下の桁数のいずれかである可能性があります。そのためには、の変換を実行することができますintタイプから。

ソリューション - 単にそのようにId列を削除し、新しいGuidタイプでそれを再作成、変更の移行:

public partial class ChangeDownloadTokenIdToGuid : DbMigration 
{ 
    public override void Up() 
    { 
     DropPrimaryKey("dbo.DownloadTokens"); 

     DropColumn("dbo.DownloadTokens", "Id"); 
     AddColumn("dbo.DownloadTokens", "Id", c => c.Guid(nullable: false, identity: true)); 

     AddPrimaryKey("dbo.DownloadTokens", "Id"); 
    } 

    public override void Down() 
    { 
     DropPrimaryKey("dbo.DownloadTokens"); 

     DropColumn("dbo.DownloadTokens", "Id"); 
     AddColumn("dbo.DownloadTokens", "Id", c => c.Int(nullable: false, identity: true)); 

     AddPrimaryKey("dbo.DownloadTokens", "Id"); 
    } 
} 

P.S. Why you use DatabaseGeneratedOption.Computed attribute, not DatabaseGeneratedOption.Identity ?

7

でもスラバUtesinovの作品が、それが唯一の空のテーブルの上または中に動作します他のテーブルが変換するテーブルを参照していないケース。だから、この答えは、より複雑なデータベース設定でこのページに終わる人々を助けるでしょう。

以下は、移行クラスから使用できるユーティリティ関数です。これは、Up/Down関数から呼び出す必要があります。この関数は、IntからGuidに変換しようとしているテーブルのテーブル参照も処理します。このヘルパー関数は、変換する列が「Id」と呼ばれていると仮定しますが、それ以外の場合は一般的なものでなければなりません。あなたのケースではそう

public void Convert(bool toGuid, string parent, params string[] children) 
    { 
     if (toGuid) 
     { 
      AddColumn($"dbo.{parent}s", "Id2", c => c.Guid(nullable: false, identity: true, defaultValueSql: "newid()")); 
     } 
     else 
     { 
      AddColumn($"dbo.{parent}s", "Id2", c => c.Int(nullable: false, identity: true)); 
     } 
     foreach (var child in children) 
     { 
      DropForeignKey($"dbo.{child}s", $"{parent}_Id", $"dbo.{parent}s"); 
      DropIndex($"dbo.{child}s", new[] { $"{parent}_Id" }); 
      RenameColumn($"dbo.{child}s", $"{parent}_Id", $"old_{parent}_Id"); 
      if (toGuid) 
      { 
       AddColumn($"dbo.{child}s", $"{parent}_Id", c => c.Guid()); 
      } 
      else 
      { 
       AddColumn($"dbo.{child}s", $"{parent}_Id", c => c.Int()); 
      } 
      Sql($"update c set {parent}_Id=p.Id2 from {child}s c inner join {parent}s p on p.Id=c.old_{parent}_Id"); 
      DropColumn($"dbo.{child}s", $"old_{parent}_Id"); 
     } 
     DropPrimaryKey($"dbo.{parent}s"); 
     DropColumn($"dbo.{parent}s", "Id"); 
     RenameColumn($"dbo.{parent}s", "Id2", "Id"); 
     AddPrimaryKey($"dbo.{parent}s", "Id"); 
     foreach (var child in children) 
     { 
      CreateIndex($"dbo.{child}s", $"{parent}_Id"); 
      AddForeignKey($"dbo.{child}s", $"{parent}_Id", $"dbo.{parent}s", "Id"); 
     } 
    } 

あなたのアップ/ダウン機能は、次のようになります。

public override void Up() 
    { 
     Convert(true,"DownloadToken"); 
    } 

    public override void Down() 
    { 
     Convert(false, "DownloadToken"); 
    } 
関連する問題