EF 6.1独特的可空指数

问题描述 投票:42回答:3

在使用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中一样以原样的方式来表示脚手架WHERE PropertyName IS NOT NULL(参见:https://stackoverflow.com/a/767702/52026)?

c# sql-server entity-framework ef-code-first
3个回答
49
投票

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

  1. 安装实体框架,在app.config中定义您的DbContext,实体,conn字符串等。
  2. 启用迁移 - 在程序包管理器控制台中运行'-EnableMigration'
  3. 创建DbMigration - 在程序包管理器控制台中运行'Add-Migration MigrationName'
  4. 在ovverided 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));

注意:不要忘记创建降级,以。覆盖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尝试为唯一列和其他相等值添加两个带空值的条目。

这是我的演示代码 - Pastebin


6
投票

在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");

0
投票

不,你不能原生地做到这一点。

但我创建了一个自定义SQL生成器,它支持以下功能:

  1. 对索引ASCDESC中的列进行排序
  2. 启用WHERE关键字

为了能够使用它,您必须仅调整索引名称。该名称由:分为3部分。部分是:

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

如果你有2列的索引,需要Column1排序ASCColumn2 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文件中,在构造函数中添加以下行:

SetSqlGenerator("System.Data.SqlClient", new CustomSqlServerMigrationSqlGenerator());

最后,创建CustomSqlServerMigrationSqlGenerator.cs文件,如下所示:code here


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);");
}

如何更改迁移类代码?

在我设置的Migration文件夹中创建的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属性。

© www.soinside.com 2019 - 2024. All rights reserved.