EF 6.1では、Code Firstを使用して、エンティティの属性を使用するか、以下のようにFluent APIを使用してインデックスを作成できます。
Property(x => x.PropertyName)
.IsOptional()
.HasMaxLength(450)
.HasColumnAnnotation("Index",
new IndexAnnotation(new IndexAttribute("IX_IndexName") {IsUnique = true, }));
足場を言う方法はありますかWHERE PropertyName IS NOT NULL
SQL Serverでネイティブに行うのと同じ方法で(参照: https://stackoverflow.com/a/767702/52026 )?
このWHERE句を使用するようにEFに指示する方法が見つかりませんでしたが、いくつかの回避策があります。それがあなたのケースに収まるかどうかを確認してください。
Up
メソッドで作成されたDbMigrationクラスで、SQLを実行して、一意のnull許容インデックスを作成します。コード:
// 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一意の列と他の等しい値にnull値を持つ2つのエトリーを追加してみます。
これが私のデモコードです- Pastebin
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");
いいえ、あなたはそれを行うことができません自然に。
しかし、以下を可能にするカスタムSQLジェネレーターを作成しました。
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
ファイルで、コンストラクタに次の行を追加します。
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);");
}
移行クラスコードを変更する方法
設定したMigrationフォルダに作成されるConfiguration
クラスに
CodeGenerator = new CSharpMigrationCodeGeneratorIndexNullable();
私のCSharpMigrationCodeGeneratorIndexNullable
クラスはCSharpMigrationCodeGenerator
を拡張します。正確なクラスコンテンツを表示するつもりはないので、アイデアを提示します。 CSharpMigrationCodeGenerator
コンテンツに基づいて、いくつかのメソッドをオーバーライドしました。 Entity Frameworkプロジェクトは 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));
しかし、インデックスがnull可能でなければならないかどうかを知る方法は?
createIndexOperation
パラメータにはインデックス情報が含まれています。 CreateIndexOperation
の作成を変更することはできませんでしたが、そのTable
、Name
、およびColumns
プロパティは、エンティティクラスのフィールドに到達し、拡張可能なIndex
属性を取得するのに十分でした。