Страницы

Поиск по вопросам

вторник, 13 ноября 2018 г.

Как задать имя ключа для связи многие ко многим?

Для разработки базы данных использую подход code first. Есть два класса
public class Assembly { public int Id {get;set;}
public virtual ICollection Items {get;set;} = new List(); }
public class OperationItem { public int Id {get;set;}
public virtual ICollection Assemblies {get;set;} = new List(); }
на основании этого entity framework генерирует следующую миграцию:
CreateTable( "dbo.AssemblyOperationItems", c => new { Assembly_Id = c.Int(nullable: false), OperationItem_Id = c.Int(nullable: false), }) .PrimaryKey(t => new { t.Assembly_Id, t.OperationItem_Id }) .ForeignKey("dbo.Assemblies", t => t.Assembly_Id) .ForeignKey("dbo.OperationItems", t => t.OperationItem_Id) .Index(t => t.Assembly_Id) .Index(t => t.OperationItem_Id);
сам скрипт миграции корректный, меня не устраивает присваиваемые имена: Assembly_Id & OperationItem_Id, а в во всех остальных таблицах ключи называются AssemblyId & OperationItemId
Можно ли сказать EF что бы он генерировал имена без использования _ в имени ключа при создании связи многие ко многим.
P.S. Я знаю про то что данную проблему можно решить если создать связь через fluent api, интересует иное решение, атрибуты аннотации и т.п.


Ответ

Когда используется связь many-to-many, то используется соглашение об именовании FK, которые перегрузить не имеется возможности с помощью аннотации. Согласно соглашению об именовании, FK формируется по следующему правилу
<имя таблицы>_<имя первичного ключа таблицы>
То, что мы и наблюдаем в примере.
Чтобы это перегрузить, можно сделать следующее:
Как вы отметили, использовать FluentAPI следующим образом:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity() .HasMany(s => s.Items) .WithMany(c => c.Assemblies) .Map(cs => { cs.MapLeftKey("ItemsRefId"); cs.MapRightKey("AssembliesRefId");
}); }
В результате, у нас получится следующая миграция:
CreateTable( "dbo.AssemblyOperationItems", c => new { ItemsRefId = c.Int(nullable: false), AssembliesRefId = c.Int(nullable: false), }) .PrimaryKey(t => new { t.ItemsRefId, t.AssembliesRefId }) .ForeignKey("dbo.Assemblies", t => t.ItemsRefId, cascadeDelete: true) .ForeignKey("dbo.OperationItems", t => t.AssembliesRefId, cascadeDelete: true) .Index(t => t.ItemsRefId) .Index(t => t.AssembliesRefId); Перегрузить соглашение по именованию вторичных ключей.
Когда нас не устраивает стандартное соглашение имен, мы можем это соглашение перегрузить. Пример взять отсюда Определим класс по переименованию имен для вторичных ключей, который будет удалять символ _, который генерируется согласно стандартному соглашению имен.
// Provides a convention for fixing the independent association (IA) foreign key column names. public class ForeignKeyNamingConvention : IStoreModelConvention {
public void Apply(AssociationType association, DbModel model) { // Identify ForeignKey properties (including IAs) if (association.IsForeignKey) { // rename FK columns var constraint = association.Constraint; if (DoPropertiesHaveDefaultNames(constraint.FromProperties, constraint.ToRole.Name, constraint.ToProperties)) { NormalizeForeignKeyProperties(constraint.FromProperties); } if (DoPropertiesHaveDefaultNames(constraint.ToProperties, constraint.FromRole.Name, constraint.FromProperties)) { NormalizeForeignKeyProperties(constraint.ToProperties); } } }
private bool DoPropertiesHaveDefaultNames(ReadOnlyMetadataCollection properties, string roleName, ReadOnlyMetadataCollection otherEndProperties) { if (properties.Count != otherEndProperties.Count) { return false; }
for (int i = 0; i < properties.Count; ++i) { if (!properties[i].Name.EndsWith("_" + otherEndProperties[i].Name)) { return false; } } return true; }
private void NormalizeForeignKeyProperties(ReadOnlyMetadataCollection properties) { for (int i = 0; i < properties.Count; ++i) { int underscoreIndex = properties[i].Name.IndexOf('_'); if (underscoreIndex > 0) { properties[i].Name = properties[i].Name.Remove(underscoreIndex, 1); } } } }
Включаем класс перегрузке именования вторичных ключей в нашу модель следующим образом
protected override void OnModelCreating(DbModelBuilder modelBuilder) { /*modelBuilder.Entity() .HasMany(s => s.Items) .WithMany(c => c.Assemblies) .Map(cs => { cs.MapLeftKey("ItemsRefId"); cs.MapRightKey("AssembliesRefId");
}); */
modelBuilder.Conventions.Add(); }
В результате, мы получаем следующую миграцию
CreateTable( "dbo.OperationItemAssemblies", c => new { OperationItemId = c.Int(nullable: false), AssemblyId = c.Int(nullable: false), }) .PrimaryKey(t => new { t.OperationItemId, t.AssemblyId }) .ForeignKey("dbo.OperationItems", t => t.OperationItemId, cascadeDelete: true) .ForeignKey("dbo.Assemblies", t => t.AssemblyId, cascadeDelete: true) .Index(t => t.OperationItemId, name: "IX_OperationItem_Id") .Index(t => t.AssemblyId, name: "IX_Assembly_Id");
Как вы могли заметить, имена вторичных ключей теперь стали без символа '_'.

Комментариев нет:

Отправить комментарий