簡體   English   中英

實體框架代碼優先和Firebird-外鍵名稱問題

[英]Entity Framework Code First and Firebird - Foreign Key name issue

我正在嘗試使用EF代碼優先和以下簡單代碼創建包含2個表( DistrictsDatabases )的新數據庫:

using (var db = new FirebirdDBContext(_connectionString))
{
    db.Database.CreateIfNotExists();
}

我的課程:

public class District
{
    [Key]
    public int District_id { get; set; }

    [Column(TypeName = "VARCHAR")]
    [StringLength(50)]
    public string District_name { get; set; }

    [ForeignKey("DataBase")]
    public int DataBase_id { get; set; }

    public DataBase DataBase { get; set; }
}

public class DataBase
{
    [Key]
    public int DataBase_id { get; set; }

    [Column(TypeName = "VARCHAR")]
    [StringLength(50)]
    public string DataBase_name { get; set; }

    public ICollection<District> District { get; set; }

    public DataBase()
    {
        District = new List<District>();
    }
}    

但不幸的是,它引發了一個錯誤:

指定的參數超出有效值范圍。
參數名稱:名稱“ FK_Districts_DataBases_DataBase_id”長於Firebird對象名稱的31個字符的限制。

我知道Firebird的31個字符限制,但是如果我先使用Entity Framework代碼,如何解決此問題?

對於元數據字段名稱,增加Firebird的31個字符限制一直是一項不變的功能要求,並且沒有真正的方法來增加長度限制。

話雖如此,我們也許能夠控制EF試圖生成的外鍵約束名稱的長度。這將涉及將類屬性重命名為較短的名稱(但仍將它們映射為它們的真實列名稱)。

希望EF從類的屬性名稱生成外鍵約束名稱,而不是實際的列。

FK_Districts_DataBases_DataBase_id是23 + 11 = 34個字符。 我們需要將其包含在32個字符以內。

我認為這個前綴也許是不可避免的。 FK_Districts_DataBases_,所以我們有7-8個字符后綴的余地。

嘗試這個:

public class District
{
    [Key]
    public int District_id { get; set; }

    [Column(TypeName = "VARCHAR")]
    [StringLength(50)]
    public string District_name { get; set; }

    [ForeignKey("DataBase")]
    [Column("DataBase_id")]
    public int DbId { get; set; } // reduce the column name

    public DataBase DataBase { get; set; }
}

public class DataBase
{
    [Key]
    [Column("DataBase_id")]
    public int DbId { get; set; } // reduce the column name

    [Column(TypeName = "VARCHAR")]
    [StringLength(50)]
    public string DataBase_name { get; set; }    

    public ICollection<District> District { get; set; }

    public DataBase()
    {
        District = new List<District>();
    }
} 

希望EF將約束名稱設為“ FK_Districts_DataBases_DbId”(27個字符)

添加遷移后,您可以修改遷移類文件以更改外鍵名稱,如下所示:

.PrimaryKey(t => t.ID)
            .ForeignKey("dbo.CONTESTS", t => t.CONTEST_ID, cascadeDelete: true, name:"FK_CONTESTS_ID")
            .Index(t => t.CONTEST_ID);

只需添加名稱:“ your_key”,並在這樣的Down方法中避免自動生成的字段名稱的錯誤

DropForeignKey("dbo.BIBLIO_LIST","FK_CONTESTS_ID");

另一個解決方案是重寫Firebird SQL生成器。

如果您不想再次為SQL生成創建整個邏輯,則可以創建一個從FbMigrationSqlGenerator派生的類,並覆蓋所需的方法。

下面,我使用一個簡短的表名邏輯來創建外鍵名稱:

public class FirebirdSqlGenerator : FbMigrationSqlGenerator
{
    protected override IEnumerable<MigrationStatement> Generate(AddForeignKeyOperation operation)
    {
        // Reduce the name using this method
        operation.Name = GenerateForeignKeyNameFromOperation(operation);

        using (var writer = SqlWriter())
        {
            writer.Write("ALTER TABLE ");
            writer.Write(Quote(CheckName(ExtractName(operation.DependentTable))));
            writer.Write(" ADD CONSTRAINT ");
            writer.Write(Quote(CheckName(CreateItemName(operation.Name))));
            writer.Write(" FOREIGN KEY (");
            WriteColumns(writer, operation.DependentColumns.Select(Quote));
            writer.Write(") REFERENCES ");
            writer.Write(Quote(CheckName(ExtractName(operation.PrincipalTable))));
            writer.Write(" (");
            WriteColumns(writer, operation.PrincipalColumns.Select(Quote));
            writer.Write(")");
            if (operation.CascadeDelete)
            {
                writer.Write(" ON DELETE CASCADE");
            }
            yield return Statement(writer.ToString());
        }
    }

    public string GenerateForeignKeyNameFromOperation(AddForeignKeyOperation foreignKeyOperation)
    {
        var depTable = GetShortNameFromTableName(CreateItemName(foreignKeyOperation.DependentTable));
        foreignKeyOperation.Name = "FK_" +
                         depTable +
                         "_" +
                         GetShortNameFromTableName(CreateItemName(foreignKeyOperation.PrincipalTable)) +
                         "_" +
                         String.Join("_", foreignKeyOperation.DependentColumns);

        return foreignKeyOperation.Name;
    }

    [...]
}

使用SetSqlGenerator方法將其設置為SQL Generator。 它看起來像這樣:

internal sealed class MyConfiguration : DbMigrationsConfiguration<MyDbContext>
{
    private string firebirdProviderInvariantName = "FirebirdSql.Data.FirebirdClient";

    /// <summary>
    /// Initializes a new instance of the <see cref="Configuration"/> class.
    /// </summary>
    public MyConfiguration()
    {
        SetSqlGenerator(firebirdProviderInvariantName, new FirebirdSqlGenerator();
    }
}

額外提示:如果要調試代碼以檢查問題,可以在Generate方法中添加以下行:

        if (System.Diagnostics.Debugger.IsAttached == false)
            System.Diagnostics.Debugger.Launch();
        System.Diagnostics.Debugger.Break();

這將啟動一個Debug會話,您可以在另一個Visual Studio實例中捕獲該會話。

其他一些頁面可能會對您有所幫助:Firebird Repo: https : //github.com/cincuranet/FirebirdSql.Data.FirebirdClient EF Repo: https : //github.com/aspnet/EntityFramework6

希望對您有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM