Unique Indexes Agreement in EF6

How to create custom index and key conventions for different types of indexes. I need different naming for the following types of keys or indexes:

  • PK_TableName Primary Keys
  • FK_SourceTable_Column_TargetTable for foreign keys
  • IX_TableName_Column1_Column2 Non- Historical Indexes
  • UX_TableName_Column1_Column2 Unique Indexes

By default, the Entity Framework uses the following names:

  • PK_schemaname.TableName for primary keys
  • FK_schemaname.SourceTable_schemaname.TargetTable_Column1 for foreign keys
  • IX_Column1 for unique indexes
  • ColumnName for unique indexes

I found out that I can implement IStoreModelConvention <T> , but I did not find a specific type to use as a type parameter. Moreover, there is a Custom Code-First Conventions , but my research did not end to no avail. How can I get the naming rules mentioned when I use the Entity Framework Code First ? It can be anything: a package, sample, or just a referral for the next research.

+5
source share
1 answer

Mission is impossible for PC and FC. The problems are that there is no special property / EdmModel attribute / attribute / annotation to name the storage constraint - in the model they are mainly presented as a list of columns (properties), and the naming convention is hardcoded inside the classes of the migration builder. Note that some of the examples mentioned in the comments show how to rename FK columns (properties), not the FK constraint.

Fortunately for indexes, although not easy, it is possible thanks to IndexAttribute and IndexAnnotation . This is because the annotation (with the attribute) is associated with the column (the property of the object), and then it is consolidated by an inner class called ConsolidatedIndex .

So, to achieve this, you need to create IStoreModelConvention<EntityType> , prepare index summary information on properties similar to how the ConsolidatedIndex class does, determine a new name based on your rules for unnamed indexes or indexes with the default name generated for restrictions FK using ForeignKeyIndexConvention and updating the corresponding IndexAnnotation properties.

With that said, here is the code to apply your index name convention:

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

All you need to do is add it to DbModelBuilder.Conventions in OnModelCreating :

 modelBuilder.Conventions.Add<IndexNameConvention>(); 
+4
source

Source: https://habr.com/ru/post/1264122/


All Articles