2017-02-12 78 views
5

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

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

通过默认设置,实体框架使用以下namings:

  • PK_ SCHEMANAME .TableName主键
  • FK_ SCHEMANAME .SourceTable_ SCHEMANAME .TargetTable_Column1外键
  • IX_Column1非唯一索引对于唯一索引

  • 的ColumnName我发现我可以实现IStoreModelConvention<T>,但我还没有发现特定类型的类型参数来使用。 此外,可能有Custom Code-First Conventions,但我的研究结果没有结果。当我使用实体框架时,如何获得提及的命名规则Code First?它可以是任何东西:包装,样品,或只是方向为以下研究。

  • +0

    HTTP:/ /stackoverflow.com/questions/22618237/how-to-create-index-in-entity-framework-6-2-with-code-first –

    +0

    你可以在这里看到:http://stackoverflow.com/a/18245172/ 5311735如何使用IStoreModelConvention修改外键名称的示例。也许你可以用这种方式修改其他索引名称。 – Evk

    +0

    我试过但没有成功。我也试过自定义的SQL生成器。但由于缺乏信息,我没有任何结果 –

    回答

    4

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

    幸运的指标,但并不简单,但很有可能,这要感谢IndexAttributeIndexAnnotation。这是因为注释(带有属性)与列(实体属性)相关联,然后由名为ConsolidatedIndex的内部类进行合并。

    因此,为了实现这个目标,你必须创建IStoreModelConvention<EntityType>,准备从类似ConsolidatedIndex类是怎么做的,要根据你的规则为未命名的索引或索引使用默认名称,新名称的属性综合指数信息由ForeignKeyIndexConvention为FK约束生成,并更新属性的相应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<EntityType> 
    { 
        public void Apply(EntityType item, DbModel model) 
        { 
         // Build index info, consolidating indexes with the same name 
         var indexInfo = new List<IndexInfo>(); 
         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<IndexEntry> Entries = new List<IndexEntry>(); 
        } 
    
        class IndexEntry 
        { 
         public EdmProperty Column; 
         public MetadataProperty Annotation; 
         public IndexAttribute Index; 
         public bool Modified; 
        } 
    } 
    

    所有你需要的是在你的OnModelCreating添加到DbModelBuilder.Conventions

    modelBuilder.Conventions.Add<IndexNameConvention>(); 
    
    +1

    男孩!这一定需要很多耐心! –

    +0

    @GertArnold事实上,对我来说,编写答案要比探索EF源代码和编写代码要困难得多:) –

    +0

    @IvanStoev我也试图通过消息来源,但它很难... –