实体框架在本地和数据库上的独特验证
-
21-12-2019 - |
题
目前我正在尝试为我的dBContext上的Asvateentity方法的一部分来处理实体的独特验证。我尝试解决的问题是在同时添加多个实体时,在命中数据库之前检测唯一的约束错误。在添加实体a和b时,是一个例子,确保a和b没有相同的名称。目前,我的唯一索引在数据库中最少地应用于它,我有以下代码可以在数据库中介绍时涵盖:
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."));
}
.
编辑
当“唯一键”由外键组成时是一个更复杂的情况。当对数据库进行时,您需要使用外键字段,但是当对本地缓存时,您不能总是说出ReferenceId == ReferenceId
时,如果也刚刚添加参考实体,则为零。检查本地缓存是否是以下的正确方法是以下,或者我需要急于加载引用,因为在验证期间延迟加载关闭?
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;
}
.
第二个功能涉及由外键参考的唯一密钥的情况。
不隶属于 StackOverflow