webentwicklung-frage-antwort-db.com.de

EF 6.1 Eindeutiger nullwertfähiger Index

In EF 6.1 können Sie mithilfe von Code First Indizes erstellen, indem Sie Attribute in Ihren Entitäten verwenden oder die fließende API wie folgt verwenden:

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

Gibt es eine Möglichkeit, Scaffold WHERE PropertyName IS NOT NULL auf die gleiche Weise wie in SQL Server zu sagen (siehe: https://stackoverflow.com/a/767702/52026 )?

40
MrEdmundo

Ich habe keinen Weg gefunden, EF die Verwendung der Where-Klausel mitzuteilen, aber hier ist eine Problemumgehung. Prüfen Sie, ob es in Ihren Fall passt.

  1. Installieren Sie Entity Framework, definieren Sie Ihren DbContext, die Entitäten, die Verbindungszeichenfolge in app.config usw.
  2. Migration aktivieren - In Package Manager Console "-EnableMigration" ausführen
  3. DbMigration erstellen - Führen Sie in der Package Manager Console "Add-Migration MigrationName" aus.
  4. Führen Sie in der erstellten DbMigration-Klasse in der ovverided Up-Methode Ihre SQL-Anweisung aus, um einen eindeutigen nullfähigen Index zu erstellen.

code:

// 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));

Hinweis: Vergessen Sie nicht, auch ein Downgrade zu erstellen. Übergehen Sie die Down-Methode und verwenden Sie die DropIndex-Methode in:

DropIndex(tableName, indexName);

Möglicherweise benötigen Sie zusätzlichen Code, wenn sich in Ihrer Datenbank bereits Daten befinden, die mit der eindeutigen Indexeinschränkung in Konflikt stehen können.

HINWEIS: Hier können Sie die CreateIndex-Methode verwenden, aber es ist mir nicht gelungen, den richtigen Index damit zu erstellen. EF ignorieren einfach meine anonymen Argumente oder ich schreibe sie falsch. Sie können es selbst ausprobieren und hier mit Ihrem Ergebnis schreiben. Die Syntax lautet wie folgt:

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

</ strike> 5 Versuchen Sie, zwei Elemente mit Nullwerten für die eindeutige Spalte und andere gleiche Werte hinzuzufügen.

Hier ist mein Demo-Code - Pastebin

46
Viktor Bahtev

Nein , du kannst es nicht nativ tun.

Ich habe jedoch einen benutzerdefinierten SQL-Generator erstellt, der Folgendes ermöglicht:

  1. Sortieren Sie die Spalten in Ihrem Index ASC oder DESC
  2. Aktivieren Sie die Verwendung des Schlüsselworts WHERE

Um es verwenden zu können, müssen Sie nur Ihren Indexnamen ändern. Der Name wird durch : In 3 Teile getrennt. Die Teile sind:

  1. Indexname
  2. Sortierreihenfolge
  3. Where-Klausel

Wenn Sie einen Index für 2 Spalten haben, müssen Sie Column1 Nach ASC und Column2DESC sortieren und benötigen eine where -Klausel. Ihr Indexname wäre:

var uniqueName = "UN_MyIndex:ASC,DESC:Column1 IS NOT NULL";

Und Sie benutzen es einfach so:

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

Fügen Sie dann in Ihrer Configuration.cs - Datei diese Zeile in Ihren Konstruktor ein:

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

Erstellen Sie abschließend die Datei CustomSqlServerMigrationSqlGenerator.cs Wie folgt: Code hier .

0
Maxime

Basierend auf der Antwort von Viktor habe ich eine Lösung gefunden, die diesen Code automatisch erstellt.

Die endgültige Migrationsdatei sollte nicht die Methode CreateIndex, sondern die von mir angegebene Methode CreateIndexNullable verwenden. Diese Methode habe ich in DbMigrationEx erstellt, die DbMigration erweitert.

protected void CreateIndexNullable(string table, string column, string name)
{
    Sql([email protected]"CREATE UNIQUE NONCLUSTERED INDEX [{name}] ON {table}([{column}] ASC) WHERE([{column}] IS NOT NULL);");
}

Wie kann ich den Migrationsklassencode ändern?

In der Klasse Configuration, die im Migrationsordner erstellt wird, habe ich festgelegt

CodeGenerator = new CSharpMigrationCodeGeneratorIndexNullable();

Meine Klasse CSharpMigrationCodeGeneratorIndexNullable erweitert CSharpMigrationCodeGenerator. Ich werde nicht den genauen Klasseninhalt zeigen, sondern nur die Idee vorstellen. Aufgrund des Inhalts von CSharpMigrationCodeGenerator habe ich einige Methoden überschrieben. Das Entity Framework-Projekt finden Sie unter https://github.com/aspnet/EntityFramework6 .

Um die Migrationsklasse in DbMigrationEx zu ändern, habe ich die Methode verwendet

Generate(IEnumerable<MigrationOperation> operations, string @namespace, string className)

Das einzige, was geändert werden muss, ist

WriteClassStart(
    @namespace, className, writer, "DbMigration", designer: false,
    namespaces: GetNamespaces(operations));

Um die Migrationsmethode auf CreateIndexNullable zu ändern, habe ich die Methode verwendet

Generate(CreateIndexOperation createIndexOperation, IndentedTextWriter writer)

Sie müssen die Zeile ändern

writer.Write("CreateIndex(");

Ebenfalls

WriteIndexParameters(createIndexOperation, writer);

zu

writer.Write(", ");
writer.Write(Quote(createIndexOperation.Name));

Aber woher wissen, ob der Index nullbar sein muss?

Der Parameter createIndexOperation enthält Indexinformationen. Ich konnte das Erstellen von CreateIndexOperation nicht ändern, aber die Eigenschaften Table, Name und Columns könnten ausreichen, um auf Felder in der Entitätsklasse zuzugreifen und Index Attribut, das erweitert werden kann.

0
gangus

In EF Core können Sie die HasFilter-Methode in der fließenden API verwenden, um das zu erreichen, wonach Sie suchen, ohne der Migration benutzerdefiniertes SQL hinzuzufügen.

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

Dadurch wird eine Migration wie folgt generiert:

migrationBuilder.CreateIndex(
    name: "IX_IndexName",
    table: "Table",
    columns: new[] { "PropertyName" },
    filter: "PropertyName IS NOT NULL");
0
Sam