Di chuyển khung thực thể đổi tên bảng và cột


118

Tôi đã đổi tên một vài thực thể và các thuộc tính điều hướng của chúng và tạo một Di chuyển mới trong EF 5. Như thường lệ với việc đổi tên trong di chuyển EF, theo mặc định, nó sẽ bỏ các đối tượng và tạo lại chúng. Đó không phải là điều tôi muốn vì vậy tôi đã phải xây dựng tệp di chuyển từ đầu.

    public override void Up()
    {
        DropForeignKey("dbo.ReportSectionGroups", "Report_Id", "dbo.Reports");
        DropForeignKey("dbo.ReportSections", "Group_Id", "dbo.ReportSectionGroups");
        DropForeignKey("dbo.Editables", "Section_Id", "dbo.ReportSections");
        DropIndex("dbo.ReportSectionGroups", new[] { "Report_Id" });
        DropIndex("dbo.ReportSections", new[] { "Group_Id" });
        DropIndex("dbo.Editables", new[] { "Section_Id" });

        RenameTable("dbo.ReportSections", "dbo.ReportPages");
        RenameTable("dbo.ReportSectionGroups", "dbo.ReportSections");
        RenameColumn("dbo.ReportPages", "Group_Id", "Section_Id");

        AddForeignKey("dbo.ReportSections", "Report_Id", "dbo.Reports", "Id");
        AddForeignKey("dbo.ReportPages", "Section_Id", "dbo.ReportSections", "Id");
        AddForeignKey("dbo.Editables", "Page_Id", "dbo.ReportPages", "Id");
        CreateIndex("dbo.ReportSections", "Report_Id");
        CreateIndex("dbo.ReportPages", "Section_Id");
        CreateIndex("dbo.Editables", "Page_Id");
    }

    public override void Down()
    {
        DropIndex("dbo.Editables", "Page_Id");
        DropIndex("dbo.ReportPages", "Section_Id");
        DropIndex("dbo.ReportSections", "Report_Id");
        DropForeignKey("dbo.Editables", "Page_Id", "dbo.ReportPages");
        DropForeignKey("dbo.ReportPages", "Section_Id", "dbo.ReportSections");
        DropForeignKey("dbo.ReportSections", "Report_Id", "dbo.Reports");

        RenameColumn("dbo.ReportPages", "Section_Id", "Group_Id");
        RenameTable("dbo.ReportSections", "dbo.ReportSectionGroups");
        RenameTable("dbo.ReportPages", "dbo.ReportSections");

        CreateIndex("dbo.Editables", "Section_Id");
        CreateIndex("dbo.ReportSections", "Group_Id");
        CreateIndex("dbo.ReportSectionGroups", "Report_Id");
        AddForeignKey("dbo.Editables", "Section_Id", "dbo.ReportSections", "Id");
        AddForeignKey("dbo.ReportSections", "Group_Id", "dbo.ReportSectionGroups", "Id");
        AddForeignKey("dbo.ReportSectionGroups", "Report_Id", "dbo.Reports", "Id");
    }

Tất cả những gì tôi đang cố gắng làm là đổi tên dbo.ReportSectionsthành dbo.ReportPagesvà sau đó dbo.ReportSectionGroupsthành dbo.ReportSections. Sau đó, tôi cần phải đổi tên cột khoá ngoại trên dbo.ReportPagestừ Group_Idđể Section_Id.

Tôi đang bỏ các khóa và chỉ mục ngoại liên kết các bảng lại với nhau, sau đó tôi đổi tên các bảng và cột khóa ngoại, sau đó tôi lại thêm các chỉ mục và khóa ngoại. Tôi giả sử điều này sẽ hoạt động nhưng tôi gặp lỗi SQL.

Msg 15248, Cấp 11, Trạng thái 1, Quy trình sp_rename, Dòng 215 Hoặc tham số @objname không rõ ràng hoặc @objtype (COLUMN) được tuyên bố là sai. Msg 4902, Cấp 16, Trạng thái 1, Dòng 10 Không thể tìm thấy đối tượng "dbo.ReportSections" vì nó không tồn tại hoặc bạn không có quyền.

Tôi không có một thời gian dễ dàng để tìm ra những gì sai ở đây. Bất kỳ cái nhìn sâu sắc sẽ rất hữu ích.


Những dòng trên thất bại? Bạn có thể theo dõi quá trình di chuyển trong SQL Server Profiler và kiểm tra SQL tương ứng không?
Albin Sunnanbo

Câu trả lời:


143

Đừng bận tâm. Tôi đã làm cho cách này phức tạp hơn nó thực sự cần phải được.

Đây là tất cả những gì tôi cần. Các phương thức đổi tên chỉ tạo ra một cuộc gọi đến thủ tục được lưu trữ của hệ thống sp_rename và tôi đoán rằng đã xử lý tất cả mọi thứ, bao gồm các khóa ngoại có tên cột mới.

public override void Up()
{
    RenameTable("ReportSections", "ReportPages");
    RenameTable("ReportSectionGroups", "ReportSections");
    RenameColumn("ReportPages", "Group_Id", "Section_Id");
}

public override void Down()
{
    RenameColumn("ReportPages", "Section_Id", "Group_Id");
    RenameTable("ReportSections", "ReportSectionGroups");
    RenameTable("ReportPages", "ReportSections");
}

29
Hãy cẩn thận với tên bảng có dấu chấm trong đó. RenameColumntạo ra một sp_renamecâu lệnh T-SQL sử dụng sử dụng parsenamenội bộ có một số hạn chế. Vì vậy, nếu bạn có một tên bảng có dấu chấm trong đó, ví dụ: "SubSystemA.Tablename" thì hãy sử dụng:RenameColumn("dbo.[SubSystemA.Tablename]", "OldColumnName", "NewColumnName");
Ilan

10
Điều này dường như cập nhật các cột được tham chiếu trong Khóa ngoài, nhưng nó không đổi tên chính FK. Đó là một sự xấu hổ, nhưng có lẽ không phải là ngày tận thế trừ khi bạn thực sự cần phải đề cập đến một FK sau đó bằng tên của nó.
mikeigs

9
@mikeigs bạn có thể sử dụng RenameIndex(..)trong quá trình di chuyển của mình để đổi tên nó
JoeBrockhaus

1
Tôi nhận được một ngoại lệ khi đổi tên cột. có lẽ vì bảng đổi tên vẫn không được áp dụng. Tôi đã phải chia nó thành hai lần di cư
Josue Martinez

Với EF6, sử dụng RenameTable(..)để đổi tên FK và PK. Nghe có vẻ không đúng nhưng đó là những gì làm việc cho tôi. Đây là phương pháp tạo ra T-SQL ( execute sp_rename ...) chính xác . Nếu bạn cập nhật cơ sở dữ liệu -verbose, bạn sẽ tự mình nhìn thấy nó.
Giovanni

44

Nếu bạn không thích viết / thay đổi mã yêu cầu trong lớp Di chuyển theo cách thủ công, bạn có thể làm theo cách tiếp cận hai bước để tự động tạo RenameColumnmã được yêu cầu:

Bước một Sử dụng ColumnAttributeđể giới thiệu tên cột mới và sau đó thêm di chuyển (ví dụ Add-Migration ColumnChanged)

public class ReportPages
{
    [Column("Section_Id")]                 //Section_Id
    public int Group_Id{get;set}
}

Bước hai thay đổi tên thuộc tính và áp dụng lại cho cùng một di chuyển (ví dụ Add-Migration ColumnChanged -force) trong Bảng điều khiển quản lý gói

public class ReportPages
{
    [Column("Section_Id")]                 //Section_Id
    public int Section_Id{get;set}
}

Nếu bạn nhìn vào lớp Migration, bạn có thể thấy mã tự động được tạo là RenameColumn.


Làm thế nào bạn có thể thêm cùng một di chuyển hai lần? Khi tôi thử điều này, tôi nhận được:The name 'Rename_SalesArea' is used by an existing migration.
Andrew S

hãy xem -forcetham số khi sử dụng tiện ích bổ sung
Hossein Narimani Rad

2
cũng chú ý bài đăng này không dành cho lõi EF
Hossein Narimani Rad

6
Tôi nghĩ bạn chỉ cần một lần di chuyển, nhưng vẫn còn hai bước. 1. Thêm thuộc tính và tạo "đổi tên di chuyển" 2. Chỉ cần thay đổi tên thuộc tính. Đó là nó. Dù bằng cách nào, điều này chỉ giúp tôi tiết kiệm rất nhiều thời gian. Cảm ơn!
Ninja giòn

1
Tôi đã làm theo các bước được đề cập ở đây và nó đã thành công. Tôi đã không mất bất kỳ dữ liệu hiện có. rằng những gì tôi thực sự muốn, thực hiện các thay đổi mà không mất dữ liệu. Nhưng tôi chạy di chuyển khác nhau sau khi đổi tên tên thuộc tính của lớp, cho bên an toàn.
Manojb86

19

Để mở rộng một chút về câu trả lời của Hossein Narimani Rad, bạn có thể đổi tên cả bảng và cột bằng System.ComponentModel.DataAnnotations.Schema.TableAttribution và System.ComponentModel.DataAnnotations.Schema.ColumnAttribution.

Điều này có một vài lợi ích:

  1. Điều này không chỉ tạo ra việc di chuyển tên tự động, mà
  2. nó cũng sẽ xóa một cách ngon lành bất kỳ khóa ngoại nào và tạo lại chúng theo tên bảng và cột mới, đặt tên khóa ngoài và tạo thành tên riêng.
  3. Tất cả điều này mà không mất bất kỳ dữ liệu bảng

Ví dụ [Table("Staffs")]: thêm :

[Table("Staffs")]
public class AccountUser
{
    public long Id { get; set; }

    public long AccountId { get; set; }

    public string ApplicationUserId { get; set; }

    public virtual Account Account { get; set; }

    public virtual ApplicationUser User { get; set; }
}

Sẽ tạo di chuyển:

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropForeignKey(
            name: "FK_AccountUsers_Accounts_AccountId",
            table: "AccountUsers");

        migrationBuilder.DropForeignKey(
            name: "FK_AccountUsers_AspNetUsers_ApplicationUserId",
            table: "AccountUsers");

        migrationBuilder.DropPrimaryKey(
            name: "PK_AccountUsers",
            table: "AccountUsers");

        migrationBuilder.RenameTable(
            name: "AccountUsers",
            newName: "Staffs");

        migrationBuilder.RenameIndex(
            name: "IX_AccountUsers_ApplicationUserId",
            table: "Staffs",
            newName: "IX_Staffs_ApplicationUserId");

        migrationBuilder.RenameIndex(
            name: "IX_AccountUsers_AccountId",
            table: "Staffs",
            newName: "IX_Staffs_AccountId");

        migrationBuilder.AddPrimaryKey(
            name: "PK_Staffs",
            table: "Staffs",
            column: "Id");

        migrationBuilder.AddForeignKey(
            name: "FK_Staffs_Accounts_AccountId",
            table: "Staffs",
            column: "AccountId",
            principalTable: "Accounts",
            principalColumn: "Id",
            onDelete: ReferentialAction.Cascade);

        migrationBuilder.AddForeignKey(
            name: "FK_Staffs_AspNetUsers_ApplicationUserId",
            table: "Staffs",
            column: "ApplicationUserId",
            principalTable: "AspNetUsers",
            principalColumn: "Id",
            onDelete: ReferentialAction.Restrict);
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropForeignKey(
            name: "FK_Staffs_Accounts_AccountId",
            table: "Staffs");

        migrationBuilder.DropForeignKey(
            name: "FK_Staffs_AspNetUsers_ApplicationUserId",
            table: "Staffs");

        migrationBuilder.DropPrimaryKey(
            name: "PK_Staffs",
            table: "Staffs");

        migrationBuilder.RenameTable(
            name: "Staffs",
            newName: "AccountUsers");

        migrationBuilder.RenameIndex(
            name: "IX_Staffs_ApplicationUserId",
            table: "AccountUsers",
            newName: "IX_AccountUsers_ApplicationUserId");

        migrationBuilder.RenameIndex(
            name: "IX_Staffs_AccountId",
            table: "AccountUsers",
            newName: "IX_AccountUsers_AccountId");

        migrationBuilder.AddPrimaryKey(
            name: "PK_AccountUsers",
            table: "AccountUsers",
            column: "Id");

        migrationBuilder.AddForeignKey(
            name: "FK_AccountUsers_Accounts_AccountId",
            table: "AccountUsers",
            column: "AccountId",
            principalTable: "Accounts",
            principalColumn: "Id",
            onDelete: ReferentialAction.Cascade);

        migrationBuilder.AddForeignKey(
            name: "FK_AccountUsers_AspNetUsers_ApplicationUserId",
            table: "AccountUsers",
            column: "ApplicationUserId",
            principalTable: "AspNetUsers",
            principalColumn: "Id",
            onDelete: ReferentialAction.Restrict);
    }

1
Có vẻ như nó phải là mặc định để thêm thuộc tính bảng, làm cho mọi thứ đơn giản hơn nhiều.
patrick

17

Trong EF Core, tôi sử dụng các câu lệnh sau để đổi tên bảng và cột:

Đối với việc đổi tên bảng:

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.RenameTable(name: "OldTableName", schema: "dbo", newName: "NewTableName", newSchema: "dbo");
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.RenameTable(name: "NewTableName", schema: "dbo", newName: "OldTableName", newSchema: "dbo");
    }

Đối với việc đổi tên cột:

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.RenameColumn(name: "OldColumnName", table: "TableName", newName: "NewColumnName", schema: "dbo");
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.RenameColumn(name: "NewColumnName", table: "TableName", newName: "OldColumnName", schema: "dbo");
    }

3

Trong lõi ef, bạn có thể thay đổi di chuyển đã được tạo sau khi thêm di chuyển. Và sau đó làm cập nhật cơ sở dữ liệu. Một mẫu đã được đưa ra dưới đây:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.RenameColumn(name: "Type", table: "Users", newName: "Discriminator", schema: "dbo");
}

protected override void Down(MigrationBuilder migrationBuilder)
{            
    migrationBuilder.RenameColumn(name: "Discriminator", table: "Users", newName: "Type", schema: "dbo");
}

2

Tôi chỉ thử tương tự trong EF6 (đổi tên thực thể đầu tiên). Tôi chỉ cần đổi tên lớp và thêm một di chuyển bằng bảng điều khiển quản lý gói và voila, một di chuyển sử dụng RenameTable (...) đã được tạo tự động cho tôi. Tôi phải thừa nhận rằng tôi đã đảm bảo rằng thay đổi duy nhất đối với thực thể là đổi tên nó để không có cột mới hoặc đổi tên cột nên tôi không thể chắc chắn liệu đây có phải là điều của EF6 hay chỉ là (luôn luôn) có thể phát hiện các di chuyển đơn giản như vậy.


2
Tôi có thể xác nhận điều này với 6.1.3. Nó cũng đổi tên bảng một cách chính xác (đừng quên đổi tên DbSettrong bảng của bạn DatabaseContext). Thay đổi khóa chính không gây rắc rối. Việc di chuyển sẽ cố gắng xóa nó và tạo một cái mới. Vì vậy, bạn cần điều chỉnh điều đó và làm như câu trả lời của Chev là, đổi tên cột.
CularBytes

1

Tên bảng và tên cột có thể được chỉ định như là một phần của ánh xạ DbContext. Sau đó, không cần phải làm điều đó trong di cư.

public class MyContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Restaurant>()
            .HasMany(p => p.Cuisines)
            .WithMany(r => r.Restaurants)
            .Map(mc =>
            {
                mc.MapLeftKey("RestaurantId");
                mc.MapRightKey("CuisineId");
                mc.ToTable("RestaurantCuisines");
            });
     }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.