EF 6.1独特的可空指数

时间:2014-06-23 08:31:03

标签: c# sql-server entity-framework ef-code-first

在使用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)?

4 个答案:

答案 0 :(得分:48)

我没有找到告诉EF使用这个where子句的方法,但这里有一些解决方法。检查它是否适合你的情况。

  1. 安装实体框架,在app.config中定义您的DbContext,实体,conn字符串等。
  2. 启用迁移 - 在程序包管理器控制台'-EnableMigration'
  3. 中运行
  4. 创建DbMigration - 在程序包管理器控制台“Add-Migration MigrationName”
  5. 中运行
  6. 在ovverided Up方法创建的DbMigration类中,运行sql以创建唯一可为空的索引。
  7. 代码:

    // 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生成器,该生成器可以启用以下功能:

  1. 对索引=INDEX(E:E,MATCH(A1,F:F)) ASC中的列进行排序
  2. 启用DESC关键字

要使用它,必须仅调整索引名称。名称由WHERE分为3部分。这些部分是:

  1. 索引名称
  2. 排序订单
  3. Where子句

如果您有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的创建,但是它的TableNameColumns属性足以访问实体类中的字段并获取Index可以扩展的属性。