C# EF 6.1唯一可空索引

C# EF 6.1唯一可空索引,c#,sql-server,entity-framework,ef-code-first,C#,Sql Server,Entity Framework,Ef Code First,在EF 6.1中,首先使用代码,您可以使用实体中的属性或使用fluent API创建索引,如下所示: Property(x => x.PropertyName) .IsOptional() .HasMaxLength(450) .HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttri

在EF 6.1中,首先使用代码,您可以使用实体中的属性或使用fluent API创建索引,如下所示:

 Property(x => x.PropertyName)
                .IsOptional()
                .HasMaxLength(450)
                .HasColumnAnnotation("Index",
                    new IndexAnnotation(new IndexAttribute("IX_IndexName") {IsUnique = true,  }));

是否有任何方法可以像在SQL Server本机中一样(请参阅:)说scaffold
WHERE PropertyName不为NULL

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

  • 安装实体框架,在app.config中定义DbContext、实体、连接字符串等
  • 启用迁移-在包管理器控制台中运行“-EnableMigration”
  • 创建DbMigration-在包管理器控制台“添加迁移名称”中运行
  • 在ovverided
    Up
    方法中创建的DbMigration类中,运行sql以创建唯一的可空索引
  • 代码:

    注意:也不要忘记创建降级。Ovveride
    Down
    方法并在内部使用
    DropIndex
    方法:

    DropIndex(tableName, indexName);
    
    此外,如果数据库中已有可能与唯一索引约束冲突的数据,则可能需要一些附加代码

    注意:这里您可以使用CreateIndex方法,但我无法使用它创建正确的索引。请忽略我的匿名论点,否则我会把它们写错。你可以自己试一试,把结果写在这里。语法如下:

    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尝试为唯一列和其他相等值添加两个具有空值的度量值


    这是我的演示代码-

    在EF Core中,您可以使用fluent API中的HasFilter方法来实现您想要的功能,而无需向迁移中添加自定义SQL

    builder.Entity<Table>()
        .HasIndex(x => x.PropertyName)
        .HasName("IX_IndexName")
        .HasFilter("PropertyName IS NOT NULL");
    

    ,您不能以本机方式执行此操作

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

  • 对索引中的列进行排序
    ASC
    DESC
  • 启用
    WHERE
    关键字的使用
  • 要使用它,您必须只调整索引名。名称由
    分为三部分。这些部分是:

  • 索引名
  • 排序顺序
  • Where子句
  • 如果您在两列上有索引,则需要对
    Column1
    进行排序
    ASC
    Column2
    DESC
    ,并且需要一个
    where
    子句,您的索引名称将是:

    var uniqueName = "UN_MyIndex:ASC,DESC:Column1 IS NOT NULL";
    
    你可以这样简单地使用它:

    migrationBuilder.CreateIndex(
        name: "IX_IndexName",
        table: "Table",
        columns: new[] { "PropertyName" },
        filter: "PropertyName 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
    文件,如图所示:。

    根据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);");
    }
    
    如何更改迁移类代码

    在我设置的迁移文件夹中创建的
    配置
    类中

    CodeGenerator = new CSharpMigrationCodeGeneratorIndexNullable();
    
    My
    CSharpMigrationCodeGeneratorIndexNullable
    类扩展了
    CSharpMigrationCodeGenerator
    。 我不会展示确切的课堂内容,我只是展示一下想法。 基于
    CSharpMigrationCodeGenerator
    内容,我覆盖了一些方法。实体框架项目可访问

    要将迁移类更改为
    dbmigtorionex
    ,我使用了

    Generate(IEnumerable<MigrationOperation> operations, string @namespace, string className)
    
    Generate(CreateIndexOperation createIndexOperation, IndentedTextWriter writer)
    
    要将迁移方法更改为
    CreateIndexNullable
    I使用了

    Generate(IEnumerable<MigrationOperation> operations, string @namespace, string className)
    
    Generate(CreateIndexOperation createIndexOperation, IndentedTextWriter writer)
    
    你需要换行

    writer.Write("CreateIndex(");
    

    但如何知道索引是否必须为空


    createIndexOperation
    参数包含索引信息。我无法修改
    CreateIndexOperation
    创建,但其
    名称
    属性足以访问实体类中的字段并获得可扩展的
    索引
    属性。

    谢谢Viktor!它对我非常有效。另一方面,“anonymousArguments”依赖于提供程序,SQL Server忽略它。创建索引解决方案不起作用。我希望您删除它,因为它在一开始就让我感到困惑。谢谢ViktorReally,很遗憾匿名争论方法不起作用。似乎也缺少相关的文档。支持哪些值等。如果表名恰好是保留字,则必须对其进行转义,例如
    tableName=“dbo.\'User\”(至少对于SQL Server)很好!不要忘了创建降级,好的。上面的语句中似乎缺少了..IsUnique()
    
    WriteIndexParameters(createIndexOperation, writer);
    
    writer.Write(", ");
    writer.Write(Quote(createIndexOperation.Name));