EF6中的唯一索引约定

如何为不同类型的索引创建自定义索引和键约定。 我需要为以下键或索引类型命名不同的命名:

  • PK_TableName主键
  • 外键的FK_SourceTable_Column_TargetTable
  • IX_TableName_Column1_Column2非唯一索引
  • UX_TableName_Column1_Column2唯一索引

默认情况下,Entity Framework使用以下命名:

  • 主键的PK_ schemaname .TableName
  • 外键的FK_ schemaname .SourceTable_ schemaname .TargetTable_Column1
  • IX_Column1表示非唯一索引
  • ColumnName为唯一索引

我发现我可以实现IStoreModelConvention ,但我还没有找到特定类型作为类型参数。 此外,可以有自定义代码优先约定 ,但我的研究结束时没有结果。 当我使用Entity Framework Code First时,如何才能获得提及的命名规则? 它可以是任何东西:包装,样品或以下研究的方向。

PK和FK不可能完成任务。 问题在于没有用于命名存储约束的特殊EdmModel属性/属性/注释 – 在模型中它们基本上表示为列(属性)列表,命名约定在迁移构建器类中是硬编码的。 请注意,注释中提到的一些示例显示了如何重命名FK 列(属性) ,而不是FK约束本身。

幸运的是索引虽然不简单,但由于IndexAttributeIndexAnnotation ,它是可能的。 这是因为注释(带属性)与列(实体属性)相关联,然后由名为ConsolidatedIndex的内部类进行ConsolidatedIndex

因此,为了实现目标,您必须创建IStoreModelConvention ,从类似于ConsolidatedIndex类的属性准备合并索引信息,根据您对未命名索引的规则或生成默认名称的索引确定新名称对于FK约束的ForeignKeyIndexConvention ,并更新属性的相应IndexAnnotation

话虽如此,这里是应用索引名称约定的代码:

 using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity.Core.Metadata.Edm; using System.Data.Entity.Infrastructure; using System.Data.Entity.Infrastructure.Annotations; using System.Data.Entity.Migrations.Model; using System.Data.Entity.ModelConfiguration.Conventions; using System.Linq; public class IndexNameConvention : IStoreModelConvention { public void Apply(EntityType item, DbModel model) { // Build index info, consolidating indexes with the same name var indexInfo = new List(); foreach (var p in item.Properties) { foreach (var mp in p.MetadataProperties) { var a = mp.Value as IndexAnnotation; if (a == null) continue; foreach (var index in a.Indexes) { var info = index.Name != null ? indexInfo.FirstOrDefault(e => e.Name == index.Name) : null; if (info == null) { info = new IndexInfo { Name = index.Name }; indexInfo.Add(info); } else { var other = info.Entries[0].Index; if (index.IsUnique != other.IsUnique || index.IsClustered != other.IsClustered) throw new Exception("Invalid index configuration."); } info.Entries.Add(new IndexEntry { Column = p, Annotation = mp, Index = index }); } } } if (indexInfo.Count == 0) return; // Generate new name where needed var entitySet = model.StoreModel.Container.EntitySets.First(es => es.ElementType == item); foreach (var info in indexInfo) { var columns = info.Entries.OrderBy(e => e.Index.Order).Select(e => e.Column.Name); if (info.Name == null || info.Name == IndexOperation.BuildDefaultName(columns)) { bool unique = info.Entries[0].Index.IsUnique; var name = string.Format("{0}_{1}_{2}", unique ? "UX" : "IX", entitySet.Table, string.Join("_", columns)); if (name.Length > 128) name = name.Substring(0, 128); if (info.Name == name) continue; foreach (var entry in info.Entries) { var index = new IndexAttribute(name); if (entry.Index.Order >= 0) index.Order = entry.Index.Order; if (entry.Index.IsUniqueConfigured) index.IsUnique = entry.Index.IsUnique; if (entry.Index.IsClusteredConfigured) index.IsClustered = entry.Index.IsClustered; entry.Index = index; entry.Modified = true; } } } // Apply the changes foreach (var g in indexInfo.SelectMany(e => e.Entries).GroupBy(e => e.Annotation)) { if (g.Any(e => e.Modified)) g.Key.Value = new IndexAnnotation(g.Select(e => e.Index)); } } class IndexInfo { public string Name; public List Entries = new List(); } class IndexEntry { public EdmProperty Column; public MetadataProperty Annotation; public IndexAttribute Index; public bool Modified; } } 

您只需将它添加到DbModelBuilder.Conventions中的OnModelCreating

 modelBuilder.Conventions.Add();