Entity Framework geçişleri tabloları ve sütunları yeniden adlandırma


118

Bir çift varlığın adını ve gezinti özelliklerini yeniden adlandırdım ve EF 5'te yeni bir Migration oluşturdum. EF geçişlerinde yeniden adlandırmalarda olduğu gibi, varsayılan olarak nesneleri bırakacak ve yeniden oluşturacaktı. İstediğim bu değildi, bu yüzden geçiş dosyasını sıfırdan oluşturmak zorunda kaldım.

    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");
    }

Ben bunu yapmaya çalışıyorum Tüm Yeniden adlandırma olduğu dbo.ReportSectionsiçin dbo.ReportPagesve sonra dbo.ReportSectionGroupsiçin dbo.ReportSections. Sonra yabancı anahtar sütununu ' dbo.ReportPagesden' Group_Ide yeniden adlandırmam gerekiyor .Section_Id .

Tabloları birbirine bağlayan yabancı anahtarları ve dizinleri bırakıyorum, ardından tabloları ve yabancı anahtar sütununu yeniden adlandırıyorum, ardından dizinleri ve yabancı anahtarları yeniden ekliyorum. Bunun işe yarayacağını varsaydım ama bir SQL hatası alıyorum.

Msg 15248, Düzey 11, Durum 1, Prosedür sp_rename, Satır 215 Ya @objname parametresi belirsiz ya da talep edilen @objtype (SÜTUN) yanlış. Msg 4902, Düzey 16, Durum 1, Satır 10 "dbo.ReportSections" nesnesi bulunamıyor çünkü mevcut değil veya izinleriniz yok.

Burada neyin yanlış olduğunu anlamakta zorlanıyorum. Herhangi bir içgörü son derece yardımcı olacaktır.


Yukarıdaki satırlardan hangisi başarısız? SQL Server Profiler'da geçişi izleyebilir ve ilgili SQL'i kontrol edebilir misiniz?
Albin Sunnanbo

Yanıtlar:


143

Boşver. Bu yolu olması gerekenden daha karmaşık hale getiriyordum.

Tek ihtiyacım olan buydu. Yeniden adlandırma yöntemleri yalnızca sp_rename sistem saklı yordamına bir çağrı oluşturur ve sanırım bu, yeni sütun adıyla yabancı anahtarlar da dahil olmak üzere her şeyi halletti.

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
İçinde noktalar olan tablo adlarına dikkat edin. dahili olarak kullanan ve bazı sınırlamaları olan RenameColumnbir sp_renameT-SQL ifadesi üretir parsename. Bu nedenle, içinde noktalar olan bir tablo adınız varsa, örneğin "Alt SistemA.Tablename" o zaman şunu kullanın:RenameColumn("dbo.[SubSystemA.Tablename]", "OldColumnName", "NewColumnName");
Ilan

10
Bu, Yabancı Anahtarlarda belirtilen sütunları güncelliyor gibi görünüyor, ancak FK'nin kendisini yeniden adlandırmıyor. Bu utanç verici, ancak daha sonra adıyla bir FK'ye kesinlikle atıfta bulunmanız gerekmedikçe muhtemelen dünyanın sonu değil.
mikesigs

9
@mikesigs RenameIndex(..), taşıma işleminizde yeniden adlandırmak için kullanabilirsiniz
JoeBrockhaus

1
Sütunu yeniden adlandırırken bir istisna alıyorum. büyük olasılıkla yeniden adlandırma tablosu hala uygulanmadığından. Onu iki geçişe bölmek zorunda kaldım
Josue Martinez

EF6 ile FK'leri ve PK'leri RenameTable(..)yeniden adlandırmak için kullanın . Kulağa doğru gelmiyor ama benim için işe yarayan şey buydu. Doğru T-SQL ( execute sp_rename ...) 'i oluşturan yöntemdir . Update-database -verbose yaparsanız, bunu kendiniz görürsünüz.
Giovanni

44

Migration sınıfında gerekli kodu manuel olarak yazmaktan / değiştirmekten hoşlanmıyorsanız, gerekli olan kodu otomatik olarak oluşturan iki aşamalı bir yaklaşımı takip edebilirsiniz RenameColumn:

Birinci AdımColumnAttribute Yeni sütun adını ve ardından ekleme geçişini tanıtmak için kullanın (örn. Add-Migration ColumnChanged)

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

İkinci Adım , özellik adını değiştirin Add-Migration ColumnChanged -forceve Paket Yöneticisi Konsolunda aynı geçişe (örneğin ) tekrar uygulayın

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

Migration sınıfına bakarsanız, otomatik olarak oluşturulan kodun olduğunu görebilirsiniz RenameColumn.


Aynı geçişi iki kez nasıl ekleyebiliyorsunuz? Bunu denediğimde şunu anlıyorum:The name 'Rename_SalesArea' is used by an existing migration.
Andrew S

-forceeklenti geçişini kullanırken parametreye bir göz atın
Hossein Narimani Rad

2
bu gönderinin EF çekirdeği için olmadığına da dikkat edin
Hossein Narimani Rad

7
Bence yalnızca bir geçişe ihtiyacınız var, ancak yine de iki adım. 1. Öznitelik ekleyin ve "geçişi yeniden adlandırın" oluşturun 2. Özellik adını değiştirmeniz yeterlidir. Bu kadar. Her iki durumda da, bu bana çok zaman kazandırdı. Teşekkürler!
Crispy Ninja

1
Burada bahsedilen adımları takip ettim ve başarılı oldu. Mevcut hiçbir veriyi kaybetmedim. gerçekten istediğim şey, verileri kaybetmeden değişiklikleri yapmak. Ancak güvenli taraf için, sınıfın özellik adını yeniden adlandırdıktan sonra farklı geçişi çalıştırıyorum.
Manojb86

19

Hossein Narimani Rad'ın cevabını biraz genişletmek için sırasıyla System.ComponentModel.DataAnnotations.Schema.TableAttribute ve System.ComponentModel.DataAnnotations.Schema.ColumnAttribute kullanarak hem tabloyu hem de sütunları yeniden adlandırabilirsiniz.

Bunun birkaç faydası vardır:

  1. Bu yalnızca ad geçişlerini otomatik olarak oluşturmakla kalmaz,
  2. ayrıca tüm yabancı anahtarları lezzetli bir şekilde siler ve bunları yeni tablo ve sütun adlarına göre yeniden oluşturarak yabancı anahtarlara ve uygun isimleri kısıtlar.
  3. Tüm bunlar herhangi bir tablo verisi kaybetmeden

Örneğin, ekleyerek [Table("Staffs")]:

[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; }
}

Taşıma oluşturacak:

    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
Tablo özniteliğini eklemek varsayılan olmalı gibi görünüyor, bu da işleri çok daha basit hale getiriyor.
patrick

17

EF Core'da, tabloları ve sütunları yeniden adlandırmak için aşağıdaki ifadeleri kullanıyorum:

Tabloları yeniden adlandırmaya gelince:

    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");
    }

Sütunları yeniden adlandırmaya gelince:

    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

Ef core'da, ekleme geçişinden sonra oluşturulan geçişi değiştirebilirsiniz. Ve sonra veri tabanını güncelle. Aşağıda bir örnek verilmiştir:

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

EF6'da aynısını denedim (kod ilk varlık yeniden adlandırma). Sınıfı yeniden adlandırdım ve paket yöneticisi konsolunu kullanarak bir geçiş ekledim ve işte, RenameTable (...) kullanılarak bir geçiş benim için otomatik olarak oluşturuldu. Varlıktaki tek değişikliğin onu yeniden adlandırdığından emin olduğumu itiraf etmeliyim, bu nedenle yeni sütunlar veya yeniden adlandırılmış sütunlar yok, bu nedenle bunun bir EF6 olayı mı yoksa sadece EF'nin (her zaman) bu tür basit geçişleri algılayabildiğinden emin olamıyorum.


2
Ben O doğru tabloyu yeniden adlandırmak yok 6.1.3'e bu teyit edebilir (adlandırmak unutmayın DbSetsizin de DatabaseContexthem). Birincil anahtarı değiştirmek soruna neden olur. Taşıma, onu silmeye ve yeni bir tane oluşturmaya çalışacaktır. Bu yüzden bunu ayarlamanız ve Chev'in cevabını yapmanız gerekiyor, sütunu yeniden adlandırın.
CularBytes

1

Tablo adları ve sütun adları, eşlemesinin bir parçası olarak belirtilebilir DbContext. O halde göçlerde buna gerek yok.

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");
            });
     }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.