66 votes

Entièrement Framework Code First Api Fluent: Ajout d'index aux colonnes

Je suis en cours d'exécution EF 4.2 FC et de l'envie de créer des index sur certaines colonnes dans mes objets POCO.

Un exemple permet de dire que nous avons cette classe d'employés:

public class Employee
{
  public int EmployeeID { get; set; }
  public string EmployeeCode { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public DateTime HireDate { get; set; }
}

Nous avons souvent de faire des recherches pour les salariés, en leur EmployeeCode et depuis il y a beaucoup de salariés, il serait bon d'avoir indexé pour des raisons de performances.

Peut-on le faire avec l'api fluent en quelque sorte? ou peut-être les données les annotations?

Je sais qu'il est possible d'exécuter des commandes sql à quelque chose comme ceci:

context.Database.ExecuteSqlCommand("CREATE INDEX IX_NAME ON ...");

Je voudrais bien éviter de SQL brut comme ça.

je sais que cela n'existe pas, mais la recherche de quelque chose le long de ces lignes:

class EmployeeConfiguration : EntityTypeConfiguration<Employee>
    {
        internal EmployeeConfiguration()
        {
            this.HasIndex(e => e.EmployeeCode)
                .HasIndex(e => e.FirstName)
                .HasIndex(e => e.LastName);
        }
    }

ou peut-être l'aide d' System.ComponentModel.DataAnnotations le POCO pourrait ressembler à ceci (encore une fois je sais que cela n'existe pas):

public class Employee
{
  public int EmployeeID { get; set; }
  [Indexed]
  public string EmployeeCode { get; set; }
  [Indexed]
  public string FirstName { get; set; }
  [Indexed]
  public string LastName { get; set; }
  public DateTime HireDate { get; set; }
}

N'importe qui ont des idées sur la façon de le faire, ou si il y a des plans pour mettre en place un moyen pour ce faire, le premier code?

Mise à JOUR: Comme mentionné dans la réponse par Robba, cette fonctionnalité est implémentée en EF version 6.1

47voto

FRoZeN Points 1750

Après l’introduction des migrations dans EF 4.3, vous pouvez désormais ajouter des index lors de la modification ou de la création d’une table. Voici un extrait de la procédure pas à pas des migrations basées sur du code EF 4.3 du blogue de l'équipe ADO.NET

 namespace MigrationsCodeDemo.Migrations
{
    using System.Data.Entity.Migrations;

    public partial class AddPostClass : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "Posts",
                c => new
                    {
                        PostId = c.Int(nullable: false, identity: true),
                        Title = c.String(maxLength: 200),
                        Content = c.String(),
                        BlogId = c.Int(nullable: false),
                    })
                .PrimaryKey(t => t.PostId)
                .ForeignKey("Blogs", t => t.BlogId, cascadeDelete: true)
                .Index(t => t.BlogId)
                .Index(p => p.Title, unique: true);

            AddColumn("Blogs", "Rating", c => c.Int(nullable: false, defaultValue: 3));
        }

        public override void Down()
        {
            DropIndex("Posts", new[] { "BlogId" });
            DropForeignKey("Posts", "BlogId", "Blogs");
            DropColumn("Blogs", "Rating");
            DropTable("Posts");
        }
    }
}
 

C’est un moyen très typé d’ajouter les index, c’est ce que je recherchais lorsque j’ai posté la question pour la première fois.

31voto

jwsadler Points 321

Vous pouvez créer un attribut appelé indexé (comme vous l'avez suggéré), qui est ensuite ramassé personnalisé dans un initialiseur.

J'ai créé l'attribut suivant:

[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
public class IndexAttribute : Attribute
{
    public IndexAttribute(bool isUnique = false, bool isClustered = false, SortOrder sortOrder = SortOrder.Ascending)
    {
        IsUnique = isUnique;
        IsClustered = isClustered;
        SortOrder = sortOrder == SortOrder.Unspecified ? SortOrder.Ascending : sortOrder;

    }

    public bool IsUnique { get; private set; }
    public bool IsClustered { get; private set; }
    public SortOrder SortOrder { get; private set; }
    //public string Where { get; private set; }
}

J'ai ensuite créé une coutume de l'initialiseur, qui a obtenu une liste de noms de table créé pour les entités dans mon contexte. J'ai deux classes de base qui tous mes entités hériter, j'ai donc fait ce qui suit pour obtenir les noms des tables:

 var baseEF = typeof (BaseEFEntity);
        var baseLink = typeof (BaseLinkTable);
        var types =
            AppDomain.CurrentDomain.GetAssemblies().ToList().SelectMany(s => s.GetTypes()).Where(
                baseEF.IsAssignableFrom).Union(AppDomain.CurrentDomain.GetAssemblies().ToList().SelectMany(
                    s => s.GetTypes()).Where(
                        baseLink.IsAssignableFrom));

        var sqlScript = context.ObjectContext.CreateDatabaseScript();

        foreach (var type in types)
        {
            var table = (TableAttribute) type.GetCustomAttributes(typeof (TableAttribute), true).FirstOrDefault();
            var tableName = (table != null ? table.Name : null) ?? Pluralizer.Pluralize(type.Name);

J'ai ensuite trouvé toutes les propriétés de chaque entité qui ont cet attribut, puis d'exécuter une commande SQL pour générer l'index sur chaque propriété. Sweet!

//Check that a table exists
            if (sqlScript.ToLower().Contains(string.Format(CREATETABLELOOKUP, tableName.ToLower())))
            {

                //indexes

                var indexAttrib = typeof (IndexAttribute);
                properties = type.GetProperties().Where(prop => Attribute.IsDefined(prop, indexAttrib));
                foreach (var property in properties)
                {
                    var attributes = property.GetCustomAttributes(indexAttrib, true).ToList();

                    foreach (IndexAttribute index in attributes)
                    {
                        var indexName = string.Format(INDEXNAMEFORMAT, tableName, property.Name,
                                                      attributes.Count > 1
                                                          ? UNDERSCORE + (attributes.IndexOf(index) + 1)
                                                          : string.Empty);
                        try
                        {
                            context.ObjectContext.ExecuteStoreCommand(
                                string.Format(INDEX_STRING, indexName,
                                              tableName,
                                              property.Name,
                                              index.IsUnique ? UNIQUE : string.Empty,
                                              index.IsClustered ? CLUSTERED : NONCLUSTERED,
                                              index.SortOrder == SortOrder.Ascending ? ASC : DESC));
                        }
                        catch (Exception)
                        {
                        }
                    }
                }

Je suis même allé sur ajouter une classe en fonction index (qui peut avoir plusieurs colonnes) , les contraintes unique et contraintes par défaut tous de la même manière. Ce qui est aussi vraiment sympa, c'est que si vous mettez ces attributs sur une classe héritée de l'index ou la contrainte est appliquée à toutes les classes (tables) qui héritent.

BTW le pluralizer helper contient les éléments suivants:

public static class Pluralizer
{
    private static object _pluralizer;
    private static MethodInfo _pluralizationMethod;

    public static string Pluralize(string word)
    {
        CreatePluralizer();
        return (string) _pluralizationMethod.Invoke(_pluralizer, new object[] {word});
    }

    public static void CreatePluralizer()
    {
        if (_pluralizer == null)
        {
            var aseembly = typeof (DbContext).Assembly;
            var type =
                aseembly.GetType(
                    "System.Data.Entity.ModelConfiguration.Design.PluralizationServices.EnglishPluralizationService");
            _pluralizer = Activator.CreateInstance(type, true);
            _pluralizationMethod = _pluralizer.GetType().GetMethod("Pluralize");
        }
    }
}

20voto

highace Points 434

Pour tirer parti de la réponse de frozen, vous pouvez le coder vous-même dans une migration.

Tout d’abord, accédez à la console du gestionnaire de packages et créez une nouvelle migration avec add-migration , puis nommez-la. Une migration vide apparaîtra. Collez ceci dans:

     public override void Up()
    {
        CreateIndex("TableName", "ColumnName");
    }

    public override void Down()
    {
        DropIndex("TableName",new[] {"ColumnName"});
    }
 

Notez que si vous utilisez un champ de chaîne, il doit également être limité à une longueur de 450 caractères.

17voto

ECC-Dan Points 500

J'ai également examiné cela récemment et je n'ai trouvé aucun autre moyen. J'ai donc créé des index lors de l'ensemencement de la base de données:

 public class MyDBInitializer : DropCreateDatabaseIfModelChanges<MyContext>
{
    private MyContext _Context;

    protected override void Seed(MyContext context)
    {
        base.Seed(context);
        _Context = context;

        // We create database indexes
        CreateIndex("FieldName", typeof(ClassName));

        context.SaveChanges();
    }

    private void CreateIndex(string field, Type table)
    {
        _Context.Database.ExecuteSqlCommand(String.Format("CREATE INDEX IX_{0} ON {1} ({0})", field, table.Name));
    }    
}   
 

14voto

Robba Points 486

Notez que dans Entity Framework 6.1 (actuellement en version bêta) prendra en charge IndexAttribute pour annoter les propriétés de l'index, ce qui donnera automatiquement un index (unique) dans vos migrations Code First.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X