对C#,ASP.NET MVC和FluentValidation来说真的很新。
我有一个类似的用户模型:
public class UserDetails{
public int ID { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
}
目前,我一直在使用FluentValidation验证用户名和电子邮件,例如:
public AdminDetailsValidator(){
RuleFor(ad => ad.UserName).NotNull().Must(UniqueUserName(UserName)).WithMessage("UserName not Available");
RuleFor(ad => ad.Email).NotNull().Must(UniqueEmail(Email)).WithMessage("This Email id has already been registered"); ;
}
public bool UniqueUserName(string un)
{
if (UserDbContext.userDetails.SingleOrDefault(p => p.UserName == un) == null)
{
return true;
}
else
{
return false;
}
}
public bool UniqueEmail(string em)
{
if (UserDbContext.userDetails.SingleOrDefault(p => p.Email == em) == null)
{
return true;
}
else
{
return false;
}
}
但我宁愿想要一个更通用的UniqueValidator,我可以使用多个类和属性。或者至少,我不必为每个房产单独设置一个功能。所以我查看了自定义验证器。但我不知道,我如何使用该功能满足我的需求。 我想做这样的事情:
RuleFor(ad => ad.Email).NotNull().SetValidator(new UniquePropertyValidator<UserDbContext>(userDetails.Email).WithMessage("This Email id has already been registered");
这甚至可以做到吗?我想将DbContext作为类型参数和属性作为参数传递(或者它的一些变体,无论哪个有效)。并且该方法可以针对表检查属性并返回它是否唯一。
答案 0 :(得分:0)
您是否考虑过使用lambdas和泛型?我没有使用FluentValidation,因此这可能不是验证器的正确方法。
var dbContext = new UserDbContext();
RuleFor(ud => ud.Email)
.NotNull()
.SetValidator(
new UniquePropertyValidator<UserDetails>
(ud, ud => ud.Email, () => dbcontext.userDetails)
.WithMessage("This Email id has already been registered");
public class UniquePropertyValidator<T> {
public UniquePropertyValidator(T entity, Func<T,string> propertyAccessorFunc, Func<IEnumerable<T>> collectionAccessorFunc) {
_entity = entity;
_propertyAccessorFunc = propertyAccessorFunc;
_collectionAccessorFunc =collectionAccessorFunc;
}
public bool Validate(){
//Get all the entities by executing the lambda
var entities = _collectionAccessorFunc();
//Get the value of the entity that we are validating by executing the lambda
var propertyValue = _propertyAccessorFunc(_entity);
//Find the matching entity by executing the propertyAccessorFunc against the
//entities in the collection and comparing that with the result of the entity
//that is being validated. Warning SingleOrDefault will throw an exception if
//multiple items match the supplied predicate
//http://msdn.microsoft.com/en-us/library/vstudio/bb342451%28v=vs.100%29.aspx
var matchingEntity = entities.SingleOrDefault(e => _propertyAccessorFunc(e) == propertyValue);
return matchingEntity == null;
}
}
答案 1 :(得分:0)
我一直在努力为这个验证器找到一个优雅的解决方案,但到目前为止提供的解决方案似乎是获取所有数据然后检查唯一性。在我看来,这不是很好。
当尝试使用下面提出的实现时,我收到LINQ to Entities不支持Invoke(即在 template<typename _InputIterator, typename _Tp>
inline _Tp
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
__glibcxx_requires_valid_range(__first, __last);
for (; __first != __last; ++__first)
__init = __init + *__first;
return __init;
}
子句中执行Func<>
)的错误。有没有解决方法?
Where
答案 2 :(得分:0)
我们可以简单地通过使用 LINQ to Entities 来解决这个问题。
这是一个静态方法,用于确定给定值在指定的 DbSet
中是否唯一:
static class ValidationHelpers
{
/// <summary>
/// Determines whether the specified <paramref name="newValue"/> is unique inside of
/// the given <paramref name="dbSet"/>.
/// </summary>
/// <param name="dbSet"></param>
/// <param name="getColumnSelector">
/// Determines the column, with which we will compare <paramref name="newValue"/>
/// </param>
/// <param name="newValue">
/// Value, that will be checked for uniqueness
/// </param>
/// <param name="cancellationToken"></param>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TColumn"></typeparam>
/// <returns></returns>
public static async Task<bool> IsColumnUniqueInsideOfDbSetAsync<TEntity, TColumn>(DbSet<TEntity> dbSet,
Expression<Func<TEntity, TColumn>> getColumnSelector,
TColumn newValue,
CancellationToken cancellationToken)
where TEntity : class
{
return !await dbSet
.Select(getColumnSelector)
.AnyAsync(column => column.Equals(newValue), cancellationToken);
}
}
我们有以下实体:
public class Category
{
// ...
public string Title { get; set; }
// ...
}
还有一个 DbContext
类:
public interface ApplicationDbContext
{
// ...
public DbSet<Category> Category { get; set; }
// ...
}
假设用户想要创建一个新类别。我们要验证此类别的标题的唯一性:
RuleFor(c => c.Title)
.MustAsync
(
(newTitle, token) => ValidationHelpers.IsColumnUniqueInsideOfDbSetAsync
(_context.Category, c => c.Title, newTitle, token)
)
.WithMessage("{PropertyName} must be unique");
注意:_context
是 ApplicationDbContext
类型的对象。