在使用Code First的EF 6.1中,您可以使用实体中的属性创建索引,或使用以下行的流畅API:
Property(x => x.PropertyName)
.IsOptional()
.HasMaxLength(450)
.HasColumnAnnotation("Index",
new IndexAnnotation(new IndexAttribute("IX_IndexName") {IsUnique = true, }));
有没有办法以与SQL Server本身相同的方式表示scaffold WHERE PropertyName IS NOT NULL
(参见:https://stackoverflow.com/a/767702/52026)?
答案 0 :(得分:48)
我没有找到告诉EF使用这个where子句的方法,但这里有一些解决方法。检查它是否适合你的情况。
Up
方法创建的DbMigration类中,运行sql以创建唯一可为空的索引。代码:
// Add unique nullable index
string indexName = "IX_UQ_UniqueColumn";
string tableName = "dbo.ExampleClasses";
string columnName = "UniqueColumn";
Sql(string.Format(@"
CREATE UNIQUE NONCLUSTERED INDEX {0}
ON {1}({2})
WHERE {2} IS NOT NULL;",
indexName, tableName, columnName));
注意:不要忘记创建降级。 Ovveride Down
方法并使用DropIndex
方法:
DropIndex(tableName, indexName);
如果您的数据库中已存在可能与唯一索引约束冲突的数据,您可能还需要一些额外的代码。
注意:在这里您可以使用CreateIndex方法,但我无法使用它创建正确的索引。 EF只是忽略我的anonymousArguments或者我写错了。您可以自己尝试并在此处写下您的结果。语法如下:
CreateIndex(
table: "dbo.ExampleClasses",
columns: new string[] { "UniqueColumn" },
unique: true,
name: "IX_UniqueColumn",
clustered: false,
anonymousArguments: new
{
Include = new string[] { "UniqueColumn" },
Where = "UniqueColumn IS NOT NULL"
});
击> <击> 撞击> 5尝试为唯一列和其他相等值添加两个具有空值的etries。
这是我的演示代码 - Pastebin
答案 1 :(得分:2)
在EF Core中,您可以使用fluent API中的HasFilter方法来实现所需的功能,而无需在迁移中添加自定义SQL。
builder.Entity<Table>()
.HasIndex(x => x.PropertyName)
.HasName("IX_IndexName")
.HasFilter("PropertyName IS NOT NULL");
这将产生如下迁移:
migrationBuilder.CreateIndex(
name: "IX_IndexName",
table: "Table",
columns: new[] { "PropertyName" },
filter: "PropertyName IS NOT NULL");
答案 2 :(得分:0)
否,您不能本地这样做。
但是我创建了一个自定义SQL生成器,该生成器可以启用以下功能:
=INDEX(E:E,MATCH(A1,F:F))
或ASC
中的列进行排序DESC
关键字要使用它,必须仅调整索引名称。名称由WHERE
分为3部分。这些部分是:
如果您有2列索引,则需要:
和Column1
ASC
进行排序,并且需要Column2
子句,索引名称为:
DESC
您可以像这样简单地使用它:
where
然后,在您的var uniqueName = "UN_MyIndex:ASC,DESC:Column1 IS NOT NULL";
文件中,将此行添加到构造函数中:
Property(t => t.Column1)
.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute(uniqueName) { IsUnique = true, Order = 1 }));
Property(t => t.Column2)
.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute(uniqueName) { IsUnique = true, Order = 2 }));
最后,创建Configuration.cs
文件,如下所示:code here。
答案 3 :(得分:0)
基于Viktor的答案,我想出了自动创建此代码的解决方案。
最终迁移文件不应使用CreateIndex
方法,而应使用我命名为CreateIndexNullable
的方法。我在DbMigrationEx
中创建的此方法扩展了DbMigration
protected void CreateIndexNullable(string table, string column, string name)
{
Sql($@"CREATE UNIQUE NONCLUSTERED INDEX [{name}] ON {table}([{column}] ASC) WHERE([{column}] IS NOT NULL);");
}
如何更改迁移类代码?
在我设置的“迁移”文件夹中创建的Configuration
类中
CodeGenerator = new CSharpMigrationCodeGeneratorIndexNullable();
我的CSharpMigrationCodeGeneratorIndexNullable
类扩展了CSharpMigrationCodeGenerator
。
我不会显示确切的课程内容,我只介绍这个想法。
基于CSharpMigrationCodeGenerator
的内容,我推翻了一些方法。实体框架项目位于https://github.com/aspnet/EntityFramework6。
要将迁移类更改为DbMigrationEx
,我使用了方法
Generate(IEnumerable<MigrationOperation> operations, string @namespace, string className)
唯一需要改变的是
WriteClassStart(
@namespace, className, writer, "DbMigration", designer: false,
namespaces: GetNamespaces(operations));
要将迁移方法更改为CreateIndexNullable
,我使用了方法
Generate(CreateIndexOperation createIndexOperation, IndentedTextWriter writer)
您需要换行
writer.Write("CreateIndex(");
也
WriteIndexParameters(createIndexOperation, writer);
到
writer.Write(", ");
writer.Write(Quote(createIndexOperation.Name));
但是如何知道索引是否必须为空?
createIndexOperation
参数包含索引信息。我无法修改CreateIndexOperation
的创建,但是它的Table
,Name
和Columns
属性足以访问实体类中的字段并获取Index
可以扩展的属性。