2016-03-04 2 views
1

Я пытаюсь создать новую базу данных с 2-мя столами (Districts и Databases), используя EF-код первого и этот простой код:Entity Framework Code First и Firebird - Внешняя Ключевой вопрос имя

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

Но, к сожалению, он выдает ошибку:

Specified argument was out of the range of valid values.
Parameter name: The name 'FK_Districts_DataBases_DataBase_id' is longer than Firebird's 31 characters limit for object names.

I К.Н. ow о 31 символе Firebird, но как я могу решить эту проблему, если сначала использовать код Entity Framework?

+0

вы можете настроить имя внешнего ключа в разделе «Конфигурация имен нетрадиционных иностранных ключей» ** (https://msdn.microsoft.com/en-us/data/hh134698.aspx) –

+0

@ kienct89 thx, я буду попробуйте – whizzzkey

ответ

3

Увеличение предела символа 31 Firebird для имен полей метаданных было постоянным запросом функции, и нет реального способа увеличить предел длины.

Сказав это, мы могли бы контролировать длину имени ограничения внешнего ключа, которое 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 символов)

+0

Я предполагаю, что у Oracle будут те же проблемы (которые ограничены 30 символами). –

+0

yep. любое ограничение системы нисходящего потока будет применяться, я думаю. –

+0

@RajaNadar GREAT THX за ваш ответ, я очень благодарен вам за помощь в решении этой проблемы. Но я хочу добавить небольшое замечание - вы допустили ошибку при сокращении имени столбца. Чтобы этот код работал, мы должны уменьшить имя столбца в аннотации NOT имя поля в классе. – whizzzkey

1

После добавления миграции Вы можете изменить ваш файл класса миграции для изменения внешнего ключа имени как это:

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

Просто добавьте имя: «your_key», и в методе вниз, как это awoid ошибок для имени сгенерированного поля

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

Другим решением было бы переопределить генератор SQL Firebird.

Если вы не хотите снова создавать целую логику для генерации 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; 
    } 

    [...] 
} 

набора это, как вы SQL Generator с помощью метода SetSqlGenerator.Он будет выглядеть следующим образом:

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

Extra подсказка: Если вы хотите отлаживать код для проверки проблем, которые вы можете добавить следующие строки в методе 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

Я надеюсь, что это помогает.

Смежные вопросы