2017-02-12 108 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我也試圖通過消息來源,但它很難... –