C# 实体框架代码优先和Firebird-外键名称问题
我正在尝试首先使用EF代码和以下简单代码创建包含两个表(C# 实体框架代码优先和Firebird-外键名称问题,c#,database,entity-framework,firebird,C#,Database,Entity Framework,Firebird,我正在尝试首先使用EF代码和以下简单代码创建包含两个表(地区和数据库)的新数据库: using (var db = new FirebirdDBContext(_connectionString)) { db.Database.CreateIfNotExists(); } 我的班级: public class District { [Key] public int District_id { get; set; } [Column(TypeName = "VA
地区
和数据库
)的新数据库:
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>();
}
}
公共类地区
{
[关键]
公共int区_id{get;set;}
[列(TypeName=“VARCHAR”)]
[长度(50)]
公共字符串District_name{get;set;}
[外键(“数据库”)]
公共int数据库_id{get;set;}
公共数据库{get;set;}
}
公共类数据库
{
[关键]
公共int数据库_id{get;set;}
[列(TypeName=“VARCHAR”)]
[长度(50)]
公共字符串数据库_name{get;set;}
公共ICollection区{get;set;}
公共数据库()
{
地区=新列表();
}
}
但不幸的是,它抛出了一个错误:
指定的参数超出了有效值的范围。参数名称:“FK_地区\数据库\数据库\ id”的名称长度超过Firebird对对象名称的31个字符限制
我知道Firebird的31个字符限制,但是如果我首先使用实体框架代码,我如何解决这个问题呢 提高Firebird对元数据字段名称的31个字符限制一直是一个固定的功能要求,没有真正的方法来提高长度限制 话虽如此,我们也许能够控制EF试图生成的外键约束名称的长度。。这将涉及将类属性重命名为较短的名称(但仍将它们映射为真实的列名) 希望EF根据类的属性名而不是实际列生成外键约束名 FK_地区_数据库_数据库_id为23+11=34个字符。 我们需要将其限制在32个字符以下 我认为这个前缀可能是不可避免的。FK_地区_数据库_ 所以我们有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>();
}
}
公共类地区
{
[关键]
公共int区_id{get;set;}
[列(TypeName=“VARCHAR”)]
[长度(50)]
公共字符串District_name{get;set;}
[外键(“数据库”)]
[列(“数据库id”)]
public int DbId{get;set;}//减少列名
公共数据库{get;set;}
}
公共类数据库
{
[关键]
[列(“数据库id”)]
public int DbId{get;set;}//减少列名
[列(TypeName=“VARCHAR”)]
[长度(50)]
公共字符串数据库_name{get;set;}
公共ICollection区{get;set;}
公共数据库()
{
地区=新列表();
}
}
希望EF将约束名称设置为“FK\u Districts\u DataBases\u DbId”(27个字符)添加迁移后,您可以修改迁移类文件以更改外键名称,如下所示:
.PrimaryKey(t => t.ID)
.ForeignKey("dbo.CONTESTS", t => t.CONTEST_ID, cascadeDelete: true, name:"FK_CONTESTS_ID")
.Index(t => t.CONTEST_ID);
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();
}
}
只需添加名称:“your_key”,并在像这样的Down方法中为自动生成的字段名添加一个awoid错误
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;
}
[...]
}
这将启动一个调试会话,您可以在另一个VisualStudio实例中捕获该会话
其他一些可能对您有所帮助的页面:
火鸟回购:
EF回购:
我希望这会有所帮助。您可以在配置非常规外键名部分()中配置外键名()@kienct89 thx,我会尝试一下。我假设Oracle也会遇到同样的问题(最多30个字符)。是的。我想任何下游系统的限制都适用。@RajaNadar GREAT THX对于您的回答,我非常感谢您帮助解决这个问题。但是我想补充一点,你在减少列名时犯了一个错误。为了使这段代码正常工作,我们应该减少注释中的列名,而不是类中的字段名本身。。因此,您必须将db中的列重命名为较小的长度?@RajaNadar是的,为了更好地理解,我将描述-您编写了:[column(“DataBase_id”)]public int DbId{get;set;},我这样做了更改:[column(“DbId”)]public int DataBase_id{get;set;}什么是SqlWriter?SqlWriter是StringWriter的扩展-在示例中,我使用了一个类似于Firebird在其源代码中使用的一个:
if (System.Diagnostics.Debugger.IsAttached == false)
System.Diagnostics.Debugger.Launch();
System.Diagnostics.Debugger.Break();