EF6中唯一的索引约定 [英] Unique Indexes convention in EF6

查看:532
本文介绍了EF6中唯一的索引约定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何为不同类型的索引创建自定义索引和密钥约定。

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


  • PK_TableName 主键

  • FK_SourceTable_Column_TargetTable

  • IX_TableName_Column1_Column2 非唯一索引

  • UX_TableName_Column1_Column2 唯一索引

  • PK_TableName Primary keys
  • FK_SourceTable_Column_TargetTable for foreign keys
  • IX_TableName_Column1_Column2 Non-unique indexes
  • UX_TableName_Column1_Column2 Unique indexes

默认情况下,实体框架使用以下标号:

By defaults, Entity Framework uses following namings:


  • PK_ schemaname 。主键的

  • FK_ <对于非唯一索引,对于外键

  • IX_Column1 ,可以使用eman> schemaname .SourceTable_ schemaname .TargetTable_Column1

  • 列名称用于唯一索引

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

我可以实现 iStor的eModelConvention< T> ,但是我没有找到用作类型参数的特定类型。
此外,可以自定义代码优先约定,但我的研究结束没有结果。当我使用实体框架代码第一时,我可以如何获得提到的命名规则?它可以是任何东西:包装,样品或只是方向进行以下研究。

I've found out that I can implement IStoreModelConvention<T>, but I haven't found particular type to use as type parameter. Moreover, there're can be Custom Code-First Conventions, but my research is ended with no results. How I can get mentioned naming rules when I use Entity Framework Code First? It can be anything: package, sample, or just direction for following researches.

推荐答案

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

Mission impossible for PK and FK. The problems is that there is no special EdmModel property/attribute/annotation for naming the store constraint - in the model they are basically represented as list of columns (properties) and the naming convention is hardcoded inside the migration builder classes. Please note that some examples mentioned in the comments are showing how to rename the FK columns (properties), not the FK constraint itself.

幸运的是索引虽然不是简单,但是由于 IndexAttribute IndexAnnotation 可以实现。这是因为注释(带属性)与列(实体属性)相关联,然后由称为 ConsolidatedIndex 的内部类合并。

Luckily for indexes, although not simple, but it's possible, thanks to the IndexAttribute and IndexAnnotation. This is because the annotation (with attribute) is associated with column (entity property), and then consolidated by an internal class called ConsolidatedIndex.

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

So in order to achieve the goal, you have to create IStoreModelConvention<EntityType>, prepare a consolidated index info from properties similar to how ConsolidatedIndex class does it, determine the new name based on your rules for the unnamed indexes or indexes with default name generated for FK constrains by the ForeignKeyIndexConvention, and update the corresponding IndexAnnotation of the properties.

据说,这里是应用索引名称约定的代码:

With that being said, here is the code for applying 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;
    }
}

您需要的是将其添加到 DbModelBuilder.Conventions OnModelCreating

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

modelBuilder.Conventions.Add<IndexNameConvention>();

这篇关于EF6中唯一的索引约定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆