2017-02-12 38 views
5

Tworzenie niestandardowych konwencji indeksów i kluczy dla różnych typów indeksów. Potrzebuję innego nazewnictwa dla następujących kluczowych lub indeksowanych typów:Unikalna konwencja indeksów w EF6

  • PK_TableName klucze podstawowe
  • FK_SourceTable_Column_TargetTable dla kluczy obcych
  • IX_TableName_Column1_Column2 nieunikalne indeksów
  • UX_TableName_Column1_Column2 Unikalne indeksy

Przez domyślne, Entity Framework wykorzystuje następujące namings:

  • PK_ nazwa_schematu .TableName dla kluczy podstawowych
  • FK_ nazwa_schematu .SourceTable_ nazwa_schematu .TargetTable_Column1 dla kluczy obcych
  • IX_Column1 dla nieunikalnych indeksów
  • NazwaKolumny unikalnych indeksów

Odkryłem, że mogę realizować IStoreModelConvention<T>, ale nie znalazłem konkretnego rodzaju używany jako parametr typu. Co więcej, może być Custom Code-First Conventions, ale moje badania zakończone bez wyników. Jak mogę uzyskać wymienione zasady nazewnictwa, gdy używam Entity Framework Code First? Może to być wszystko: pakiet, próbka lub tylko kierunek dalszych badań.

+0

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

+0

Możesz zobaczyć tutaj: http://stackoverflow.com/a/18245172/ 5311735 przykład modyfikowania nazwy klucza obcego za pomocą IStoreModelConvention. Prawdopodobnie możesz w ten sposób modyfikować inne nazwy indeksów. – Evk

+0

Próbowałem, ale bez powodzenia. Próbowałem również niestandardowego generatora sql. Ale z powodu braku informacji nie mam żadnych wyników. –

Odpowiedz

4

Misja niemożliwa dla PK i FK. Problem polega na tym, że nie ma żadnej specjalnej właściwości/atrybutu/adnotacji EdmModel do nazwania ograniczenia sklepu - w modelu są one zasadniczo reprezentowane jako lista kolumn (właściwości), a konwencja nazewnictwa jest zakodowana na stałe w klasach konstruktora migracji. Zwróć uwagę, że niektóre przykłady wspomniane w komentarzach pokazują, jak zmienić nazwę kolumn FK (właściwości), a nie samego ograniczenia FK.

Na szczęście dla indeksów, chociaż nie jest to proste, ale jest to możliwe, dzięki IndexAttribute i IndexAnnotation. Wynika to z faktu, że adnotacja (z atrybutem) jest powiązana z kolumną (właściwość encji), a następnie skonsolidowana przez wewnętrzną klasę o nazwie ConsolidatedIndex.

Aby osiągnąć cel, musisz utworzyć IStoreModelConvention<EntityType>, przygotować skonsolidowane informacje o indeksie z właściwości podobnych do tego, jak robi to klasa ConsolidatedIndex, określić nową nazwę na podstawie reguł dla nienazwanych indeksów lub indeksów z domyślną nazwą wygenerowane dla ograniczeń FK przez ForeignKeyIndexConvention i zaktualizować odpowiadające im właściwości o wartości IndexAnnotation.

Mając to na uwadze powyższe, oto kod stosowania swoją nazwę indeksu konwencji:

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

Wszystko, co potrzebne jest, aby dodać go do DbModelBuilder.Conventions w swojej OnModelCreating:

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

Boy! To musiało zabrać dużo cierpliwości! –

+0

@GertArnold Właściwie to było o wiele trudniej (u mnie) skomponować odpowiedź, niż odkrywać źródło EF i pisać kod :) –

+0

@IvanStoev Próbowałem też przejść przez źródła, ale było to dość trudne ... –