Entity Framework Code First Fluent Api:向列添加索引
Posted
技术标签:
【中文标题】Entity Framework Code First Fluent Api:向列添加索引【英文标题】:Entity Framework Code First Fluent Api: Adding Indexes to columns 【发布时间】:2012-01-05 22:46:57 【问题描述】:我正在运行 EF 4.2 CF,并希望在我的 POCO 对象中的某些列上创建索引。
例如,假设我们有这个员工类:
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;
我们经常根据员工的 EmployeeCode 搜索员工,因为有很多员工,出于绩效原因将其编入索引会很好。
我们可以用 fluent api 以某种方式做到这一点吗?或者可能是数据注释?
我知道可以执行类似这样的 sql 命令:
context.Database.ExecuteSqlCommand("CREATE INDEX IX_NAME ON ...");
我非常希望避免使用这样的原始 SQL。
我知道这不存在,但正在寻找类似的东西:
class EmployeeConfiguration : EntityTypeConfiguration<Employee>
internal EmployeeConfiguration()
this.HasIndex(e => e.EmployeeCode)
.HasIndex(e => e.FirstName)
.HasIndex(e => e.LastName);
或者使用System.ComponentModel.DataAnnotations
,POCO 可能看起来像这样(我再次知道这不存在):
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;
任何人对如何做到这一点有任何想法,或者如果有任何计划实施一种方法来做到这一点,代码优先?
更新:正如 Robba 的回答中提到的,此功能在 EF 版本 6.1 中实现
【问题讨论】:
在此处查看解决方案:***.com/a/23055838/187650 【参考方案1】:在 EF 4.3 中引入迁移后,您现在可以在修改或创建表时添加索引。这是来自 ADO.NET 团队博客的EF 4.3 Code-Based Migrations Walkthrough 的摘录
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");
这是一种很好的强类型添加索引的方法,这是我第一次发布问题时所寻找的。p>
【讨论】:
我的意思是原来的问题提到了 4.2 :) 这个解决方案还不够好。如果从头开始创建数据库,迁移中添加的索引将丢失。你真的想要一个索引的数据注释。 @Jez 我完全同意,或者通过 EntityTypeConfigurations 设置它的方式 @Jez 如果数据库是从头开始创建的,那么所有的迁移都会运行并重新创建索引,所以应该没问题。 @ciscoheat 根据我的经验,这不会发生。它不运行任何迁移;它只是创建与最新版本的数据模型相对应的数据库,并将单个条目插入到迁移历史表中以进行初始创建。【参考方案2】:您可以创建一个名为 indexed 的属性(如您所建议的那样),然后在自定义初始化程序中获取该属性。
我创建了以下属性:
[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;
然后我创建了一个自定义初始化程序,它获取了为我的上下文中的实体创建的表名列表。我有两个我的所有实体都继承的基类,所以我执行了以下操作来获取表名:
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);
然后我找到每个实体上具有该属性的所有属性,然后执行 SQL 命令为每个属性生成索引。甜蜜!
//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)
我什至继续以相同的方式添加基于类的索引(可能有多个列)、唯一约束和默认约束。还有一点非常棒的是,如果您将这些属性放在继承的类上,则索引或约束将应用于继承它的所有类(表)。
顺便说一句,复数助手包含以下内容:
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");
【讨论】:
非常有趣,这正是我正在考虑的事情,使用数据注释或流利的 api 来定义模型中的索引。我将看看我是否可以很快为这种方法创建一些测试,干得好。【参考方案3】:要基于frozen 的响应,您可以自己将其编码到迁移中。
首先,转到包管理器控制台并使用add-migration
创建一个新迁移,然后为其命名。将出现一个空白迁移。坚持下去:
public override void Up()
CreateIndex("TableName", "ColumnName");
public override void Down()
DropIndex("TableName",new[] "ColumnName");
请注意,如果您使用的是字符串字段,则它的长度也需要限制为 450 个字符。
【讨论】:
这正是我想要的,因为我需要在迁移中创建索引。谢谢! 这里使用的 DropIndex 方法不正确。第二个参数是string[] columns
或string name
。 Down 方法将尝试删除名为“ColumnName”的索引。您需要在 Up 中指定索引名称或在 Down 中传入列名数组。见msdn.microsoft.com/en-us/library/hh829733(v=vs.103).aspx
Sql Server 强制最大密钥大小为 900 字节。 msdn.microsoft.com/en-us/library/ms191241(v=sql.105).aspx。您的 450 个“字符”可能因编码而异。【参考方案4】:
我最近也研究了这个,没有找到其他方法,所以我在为数据库做种时创建索引:
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));
【讨论】:
我在 CreateIndex() 中为表传递了一个类型,以便在表名上具有编译时安全性。遗憾的是,对于字段名称来说这并不容易,所以我没有实现它。 谢谢 - 这对我有用。稍微扩展了 CreateIndex 方法以支持多列和唯一索引 - 请参阅下面的答案:【参考方案5】:请注意,在 Entity Framework 6.1(目前处于测试阶段)中,将支持 IndexAttribute 来注释索引属性,这将自动在您的 Code First 迁移中生成(唯一)索引。
【讨论】:
现在可以了:EF 6.1: Creating indexes with IndexAttribute【参考方案6】:对于使用 Entity Framework 6.1+ 的任何人,您可以使用 fluent api 执行以下操作:
modelBuilder
.Entity<Department>()
.Property(t => t.Name)
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute()));
在documentation 中了解更多信息。
【讨论】:
【参考方案7】:我在网上找到了一个解决方案并对其进行了调整以满足我的需求:
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
public class IndexAttribute : Attribute
public IndexAttribute(string name, bool unique = false)
this.Name = name;
this.IsUnique = unique;
public string Name get; private set;
public bool IsUnique get; private set;
public class IndexInitializer<T> : IDatabaseInitializer<T> where T : DbContext
private const string CreateIndexQueryTemplate = "CREATE unique INDEX indexName ON tableName (columnName);";
public void InitializeDatabase(T context)
const BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance;
Dictionary<IndexAttribute, List<string>> indexes = new Dictionary<IndexAttribute, List<string>>();
string query = string.Empty;
foreach (var dataSetProperty in typeof(T).GetProperties(PublicInstance).Where(p => p.PropertyType.Name == typeof(DbSet<>).Name))
var entityType = dataSetProperty.PropertyType.GetGenericArguments().Single();
TableAttribute[] tableAttributes = (TableAttribute[])entityType.GetCustomAttributes(typeof(TableAttribute), false);
indexes.Clear();
string tableName = tableAttributes.Length != 0 ? tableAttributes[0].Name : dataSetProperty.Name;
foreach (PropertyInfo property in entityType.GetProperties(PublicInstance))
IndexAttribute[] indexAttributes = (IndexAttribute[])property.GetCustomAttributes(typeof(IndexAttribute), false);
NotMappedAttribute[] notMappedAttributes = (NotMappedAttribute[])property.GetCustomAttributes(typeof(NotMappedAttribute), false);
if (indexAttributes.Length > 0 && notMappedAttributes.Length == 0)
ColumnAttribute[] columnAttributes = (ColumnAttribute[])property.GetCustomAttributes(typeof(ColumnAttribute), false);
foreach (IndexAttribute indexAttribute in indexAttributes)
if (!indexes.ContainsKey(indexAttribute))
indexes.Add(indexAttribute, new List<string>());
if (property.PropertyType.IsValueType || property.PropertyType == typeof(string))
string columnName = columnAttributes.Length != 0 ? columnAttributes[0].Name : property.Name;
indexes[indexAttribute].Add(columnName);
else
indexes[indexAttribute].Add(property.PropertyType.Name + "_" + GetKeyName(property.PropertyType));
foreach (IndexAttribute indexAttribute in indexes.Keys)
query += CreateIndexQueryTemplate.Replace("indexName", indexAttribute.Name)
.Replace("tableName", tableName)
.Replace("columnName", string.Join(", ", indexes[indexAttribute].ToArray()))
.Replace("unique", indexAttribute.IsUnique ? "UNIQUE" : string.Empty);
if (context.Database.CreateIfNotExists())
context.Database.ExecuteSqlCommand(query);
private string GetKeyName(Type type)
PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public);
foreach (PropertyInfo propertyInfo in propertyInfos)
if (propertyInfo.GetCustomAttribute(typeof(KeyAttribute), true) != null)
return propertyInfo.Name;
throw new Exception("No property was found with the attribute Key");
然后在你的 dbcontext 中重载 OnModelCreating
protected override void OnModelCreating(DbModelBuilder modelBuilder)
Database.SetInitializer(new IndexInitializer<MyContext>());
base.OnModelCreating(modelBuilder);
将索引属性应用于您的实体类型,使用此解决方案,您可以在同一索引中拥有多个字段,只需使用相同的名称和唯一性。
【讨论】:
非常有趣的解决方案,遇到任何方法来扩展 add-migrations 功能和用于类型配置的 fluent api,以允许在使用迁移时创建索引? 我从未使用过迁移,所以我不知道,但这应该适用于迁移,但您必须检查索引是否存在并在创建之前将其删除 我在 [link]blogs.southworks.net/dschenkelman/2012/08/18/… 找到了相同的解决方案,但它不适用于我。我使用按层次结构表的方法,并且代码仅通过基类上的属性。 @RudolfDvoracek 更改以下行 const BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance;到类“const BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy;”这应该使它循环基类中的属性。 @Petoj 我已经尝试过您的建议,但没有成功。应用程序没有处理派生类型,只检查基类型的属性。【参考方案8】:将 Tsuushin 的上述答案扩展为支持多列和唯一约束:
private void CreateIndex(RBPContext context, string field, string table, bool unique = false)
context.Database.ExecuteSqlCommand(String.Format("CREATE 0NONCLUSTERED INDEX IX_1_2 ON 1 (3)",
unique ? "UNIQUE " : "",
table,
field.Replace(",","_"),
field));
【讨论】:
简洁的方法是使用不是字符串的字段和表,以获得编译时安全性,我猜说起来难做起来难,因为它必须使用 dataannotations/fluent api 的字段名/表名。 @FRoZeN 只需将类型从字符串更改为接口,创建一个空接口并在方法内部获取对象的类名并用作表名。【参考方案9】:在Petoj上扩展
我将 CreateIndexQueryTemplate 修改为
private const string CreateIndexQueryTemplate = "IF NOT EXISTS (SELECT name FROM sysindexes WHERE name = 'indexName') CREATE unique INDEX indexName ON tableName (columnName);";
并从 OnModelCreating 中删除以下内容
Database.SetInitializer(new IndexInitializer<MyContext>());
并在配置播种方法中添加了以下内容
new IndexInitializer<MyContext>().InitializeDatabase(context);
这样每次更新数据库时都会运行索引属性。
【讨论】:
为什么不更改它,让它删除并重新创建它,这样您就可以更改它包含的字段,并且每次更新都会更新它..【参考方案10】:如果您希望将此功能添加到 EF,那么您可以在这里投票http://entityframework.codeplex.com/workitem/57
【讨论】:
【参考方案11】:jwsadler 的数据注释扩展非常适合我们。我们使用 Annotations 来影响对类或属性的处理,并使用 Fluent API 来进行全局更改。
我们的注释涵盖索引(唯一和非唯一)以及 getdate() 和 (1) 的默认值。代码示例显示了我们如何将其应用于我们的情况。我们所有的类都继承自一个基类。这个实现做了很多假设,因为我们有一个非常简单的模型。我们正在使用实体框架 6.0.1。已经包含了很多 cmets。
using System;
using System.Linq;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
namespace YourNameSpace
public enum SqlOption
Active = 1,
GetDate = 2,
Index = 3,
Unique = 4,
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
public class SqlAttribute : Attribute
public SqlAttribute(SqlOption selectedOption = SqlOption.Index)
this.Option = selectedOption;
public SqlOption Option get; set;
// See enum above, usage examples: [Sql(SqlOption.Unique)] [Sql(SqlOption.Index)] [Sql(SqlOption.GetDate)]
public class SqlInitializer<T> : IDatabaseInitializer<T> where T : DbContext
// Create templates for the DDL we want generate
const string INDEX_TEMPLATE = "CREATE NONCLUSTERED INDEX IX_columnName ON [dbo].[tableName] ([columnName]);";
const string UNIQUE_TEMPLATE = "CREATE UNIQUE NONCLUSTERED INDEX UQ_columnName ON [dbo].[tableName] ([columnName]);";
const string GETDATE_TEMPLATE = "ALTER TABLE [dbo].[tableName] ADD DEFAULT (getdate()) FOR [columnName];";
const string ACTIVE_TEMPLATE = "ALTER TABLE [dbo].[tableName] ADD DEFAULT (1) FOR [columnName];";
// Called by Database.SetInitializer(new IndexInitializer< MyDBContext>()); in MyDBContext.cs
public void InitializeDatabase(T context)
// To be used for the SQL DDL that I generate
string sql = string.Empty;
// All of my classes are derived from my base class, Entity
var baseClass = typeof(Entity);
// Get a list of classes in my model derived from my base class
var modelClasses = AppDomain.CurrentDomain.GetAssemblies().ToList().
SelectMany(s => s.GetTypes()).Where(baseClass.IsAssignableFrom);
// For debugging only - examine the SQL DDL that Entity Framework is generating
// Manipulating this is discouraged.
var generatedDDSQL = ((IObjectContextAdapter)context).ObjectContext.CreateDatabaseScript();
// Define which Annotation Attribute we care about (this class!)
var annotationAttribute = typeof(SqlAttribute);
// Generate a list of concrete classes in my model derived from
// Entity class since we follow Table Per Concrete Class (TPC).
var concreteClasses = from modelClass in modelClasses
where !modelClass.IsAbstract
select modelClass;
// Iterate through my model's concrete classes (will be mapped to tables)
foreach (var concreteClass in concreteClasses)
// Calculate the table name - could get the table name from list of DbContext's properties
// to be more correct (but this is sufficient in my case)
var tableName = concreteClass.Name + "s";
// Get concrete class's properties that have this annotation
var propertiesWithAnnotations = concreteClass.GetProperties().Where(prop => Attribute.IsDefined(prop, annotationAttribute));
foreach (var annotatedProperty in propertiesWithAnnotations)
var columnName = annotatedProperty.Name;
var annotationProperties = annotatedProperty.GetCustomAttributes(annotationAttribute, true).ToList();
foreach (SqlAttribute annotationProperty in annotationProperties)
// Generate the appropriate SQL DLL based on the attribute selected
switch (annotationProperty.Option)
case SqlOption.Active: // Default value of true plus an index (for my case)
sql += ACTIVE_TEMPLATE.Replace("tableName", tableName).Replace("columnName", columnName);
sql += INDEX_TEMPLATE.Replace("tableName", tableName).Replace("columnName", columnName);
break;
case SqlOption.GetDate: // GetDate plus an index (for my case)
sql += GETDATE_TEMPLATE.Replace("tableName", tableName).Replace("columnName", columnName);
sql += INDEX_TEMPLATE.Replace("tableName", tableName).Replace("columnName", columnName);
break;
case SqlOption.Index: // Default for empty annotations for example [Sql()]
sql += INDEX_TEMPLATE.Replace("tableName", tableName).Replace("columnName", columnName);
break;
case SqlOption.Unique:
sql += UNIQUE_TEMPLATE.Replace("tableName", tableName).Replace("columnName", columnName);
break;
// switch
// foreach annotationProperty
// foreach annotatedProperty
// foreach concreteClass
// Would have been better not to go through all the work of generating the SQL
// if we weren't going to use it, but putting it here makes it easier to follow.
if (context.Database.CreateIfNotExists())
context.Database.ExecuteSqlCommand(sql);
// InitializeDatabase
// SqlInitializer
// Namespace
这是我们的上下文:
using System;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
namespace YourNameSpace
public class MyDBContext : DbContext
protected override void OnModelCreating(DbModelBuilder modelBuilder)
// Only including my concrete classes here as we're following Table Per Concrete Class (TPC)
public virtual DbSet<Attendance> Attendances get; set;
public virtual DbSet<Course> Courses get; set;
public virtual DbSet<Location> Locations get; set;
public virtual DbSet<PaymentMethod> PaymentMethods get; set;
public virtual DbSet<Purchase> Purchases get; set;
public virtual DbSet<Student> Students get; set;
public virtual DbSet<Teacher> Teachers get; set;
// Process the SQL Annotations
Database.SetInitializer(new SqlInitializer<MyDBContext>());
base.OnModelCreating(modelBuilder);
// Change all datetime columns to datetime2
modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
// Turn off cascading deletes
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
【讨论】:
【参考方案12】:为了进一步构建所有这些出色的响应,我们添加了以下代码,以便能够从关联的元数据类型中提取 Index 属性。完整详情请see my blog post,但这里是详细信息的总结。
元数据类型的使用如下:
[MetadataType(typeof(UserAccountAnnotations))]
public partial class UserAccount : IDomainEntity
[Key]
public int Id get; set; // Unique ID
sealed class UserAccountAnnotations
[Index("IX_UserName", unique: true)]
public string UserName get; set;
在这个例子中,元数据类型是一个嵌套类,但它不是必须的,它可以是任何类型。属性匹配仅通过名称完成,因此元数据类型只需具有相同名称的属性,然后应用到该属性的任何数据注释都应应用于关联的实体类。这在原始解决方案中不起作用,因为它不检查关联的元数据类型。我们使用了以下辅助方法:
/// <summary>
/// Gets the index attributes on the specified property and the same property on any associated metadata type.
/// </summary>
/// <param name="property">The property.</param>
/// <returns>IEnumerableIndexAttribute.</returns>
IEnumerable<IndexAttribute> GetIndexAttributes(PropertyInfo property)
Type entityType = property.DeclaringType;
var indexAttributes = (IndexAttribute[])property.GetCustomAttributes(typeof(IndexAttribute), false);
var metadataAttribute =
entityType.GetCustomAttribute(typeof(MetadataTypeAttribute)) as MetadataTypeAttribute;
if (metadataAttribute == null)
return indexAttributes; // No metadata type
Type associatedMetadataType = metadataAttribute.MetadataClassType;
PropertyInfo associatedProperty = associatedMetadataType.GetProperty(property.Name);
if (associatedProperty == null)
return indexAttributes; // No metadata on the property
var associatedIndexAttributes =
(IndexAttribute[])associatedProperty.GetCustomAttributes(typeof(IndexAttribute), false);
return indexAttributes.Union(associatedIndexAttributes);
【讨论】:
P.S.我们使用的是 EF 5.0,所以上面的代码在 EF 4.2 上未经测试【参考方案13】:对于 EF7,您可以使用 hasIndex()
方法。
我们也可以设置聚集索引和非聚集索引。
默认情况下,主键将被聚集。我们也可以改变这种行为。
supplierItemEntity.HasKey(supplierItem => supplierItem.SupplierItemId).ForSqlServerIsClustered(false);
supplierItemEntity.HasIndex(s => new s.ItemId ).ForSqlServerIsClustered(true);
【讨论】:
【参考方案14】:我发现@highace 给出的答案存在问题 - 向下迁移对 DropIndex 使用了错误的覆盖。这是我所做的:
-
为了遵守 Sql Server 对索引列(900 字节)的限制,我减小了模型中几个字段的大小
我使用 Add-Migration "Add Unique Indexes" 添加了迁移
我手动将 CreateIndex 和 DropIndex 方法添加到迁移中。我使用了为单列索引获取索引名称的覆盖。我使用了覆盖列名数组的覆盖,其中索引跨越多列
这里是每个方法的两个覆盖示例的代码:
public partial class AddUniqueIndexes : DbMigration
public override void Up()
//Sql Server limits indexes to 900 bytes,
//so we need to ensure cumulative field sizes do not exceed this
//otherwise inserts and updates could be prevented
//http://www.sqlteam.com/article/included-columns-sql-server-2005
AlterColumn("dbo.Answers",
"Text",
c => c.String(nullable: false, maxLength: 400));
AlterColumn("dbo.ConstructionTypes",
"Name",
c => c.String(nullable: false, maxLength: 300));
//[IX_Text] is the name that Entity Framework would use by default
// even if it wasn't specified here
CreateIndex("dbo.Answers",
"Text",
unique: true,
name: "IX_Text");
//Default name is [IX_Name_OrganisationID]
CreateIndex("dbo.ConstructionTypes",
new string[] "Name", "OrganisationID" ,
unique: true);
public override void Down()
//Drop Indexes before altering fields
//(otherwise it will fail because of dependencies)
//Example of dropping an index based on its name
DropIndex("dbo.Answers", "IX_Text");
//Example of dropping an index based on the columns it targets
DropIndex("dbo.ConstructionTypes",
new string[] "Name", "OrganisationID" );
AlterColumn("dbo.ConstructionTypes",
"Name",
c => c.String(nullable: false));
AlterColumn("dbo.Answers",
"Text",
c => c.String(nullable: false, maxLength: 500));
【讨论】:
【参考方案15】:您可以在模型构建器中指定索引
modelBuilder
.Entity<UserSalary>(builder =>
builder.HasNoKey();
builder.HasIndex("UserId").IsUnique(false);
builder.ToTable("UserSalary");
);
【讨论】:
What's new?。另外,为什么HasNoKey
?您认为创建索引是必要的。
对不起,您可以在上面的示例中删除 HasNoKey。但这就是您为列声明索引的方式以上是关于Entity Framework Code First Fluent Api:向列添加索引的主要内容,如果未能解决你的问题,请参考以下文章
Entity Framework 5.0 Code First全面学习
ADO.NET Entity Framework -Code Fisrt 开篇
转:Entity Framework 5.0 Code First全面学习