エンティティフレームワークローカルとデータベースの一意の検証
-
21-12-2019 - |
質問
現在、DBContextのValidateEntityメソッドの一部として、エンティティの一意の検証を処理しようとしています。解決しようとしている問題は、データベースにヒットする前に固有の制約エラーを検出すると同時に複数のエンティティを追加することです。例は、AとBが同じ名前を持たないことを確認して、エンティティAとBを追加する場合です。現在、データベースがそれを処理するのに必要なユニークなインデックスが適用されているので、Aがすでにデータベースにあるときにカバーできる次のコードがあります。
if (this.Components.Any(x => x.Id != item.Id && x.Name == item.Name))
{
result.ValidationErrors.Add(new DbValidationError("Name", "There already exists another component with that name."));
}
.
次のことをするよりも単純なものはありますか?
Expression<Func<Component, bool>> predicate = x => x.Name == item.Name;
if (this.Components.Where(x => x.Id != item.Id).Any(predicate) || this.Components.Local.Where(x => x != item).Any(predicate.Compile()))
{
result.ValidationErrors.Add(new DbValidationError("Name", "There already exists another component with that name."));
}
.
編集
「ユニークなキー」が外部キーで構成されている場合は、より複雑な状況です。ローカルキャッシュに対抗するときは、データベースを使用する必要がある場合、参照エンティティも追加された場合にも、ローカルキーフィールドを使用する必要があります。ローカルキャッシュをチェックする正しい方法は次のようになりますか、または検証遅延ロード中にリファレンスがオフになっているため、参照を強くロードする必要がありますか?
this.Components.Local.Any(x => x != item && x.Name == item.Name && x.ReferenceId == item.ReferenceId && x.Reference == item.Reference)
. 解決
私の問題を解決し、再利用を制限するために、一意の検証に役立つ次の拡張機能を追加しました。
public static bool UniqueCheck<TSource>(this DbSet<TSource> set, TSource item, Expression<Func<TSource, bool>> uniquePredicate) where TSource : class, IAuditEntity
{
var function = uniquePredicate.Compile();
var localContains = set.Local.Where(x => x != item).Any(function);
if (localContains) return localContains;
var remoteContains = set.Where(x => x.Id != item.Id).Any(uniquePredicate);
return remoteContains;
}
public static bool UniqueCheckWithReference<TSource>(this DbSet<TSource> set, TSource item, Expression<Func<TSource, bool>> uniquePredicate, Expression<Func<TSource, bool>> referenceUniquePredicate) where TSource : class, IAuditEntity
{
var localContains = set.Local.Where(x => x != item).Where(uniquePredicate.Compile()).Where(referenceUniquePredicate.Compile()).Any();
if (localContains) return localContains;
var remoteContains = set.Where(x => x.Id != item.Id).Where(uniquePredicate);
return false;
}
.
第2の関数は、外部キー参照からなるユニークなキーの場合を扱います。
所属していません StackOverflow