Fluent Validation C#集合中的唯一Id



我有一个实体,它有一个嵌套的集合作为我将从前端应用程序接收的属性。

我只想确保这个集合(ICollection ChildClassCollection(中的每个项目在我收到的模型中都有一个唯一的Id。

我正在使用FluentValidation,为了保持一致性,我也想使用它来添加此验证。

这是一件非常简单的事情,我找不到一个优雅的方法来解决。。

一个例子:

public class ParentClass
{
public string Name { get; set; }
public ICollection<ChildClass> ChildClassCollection { get; set; }
}
public class ChildClass
{
public int Id { get; set; }
public string Name { get; set; }
}

使用哈希集。https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.hashset-1?view=netframework-4.7.2

public class ParentClass
{
public string Name { get; set; }
public HashSet<ChildClass> ChildClassCollection { get; set; }
}
public class ChildClass
{
public int Id { get; set; }
public string Name { get; set; }
}

以下是我最终得到的结果:PRetty已清理,此外,当遇到问题时,它将退出

this.RuleFor(or => or.ChildClassCollection)
.Must(this.IsDistinct)
.WithMessage("There are more than one entity with the same Id");
public bool IsDistinct(List<UpdateRoleDTO> elements)
{
var encounteredIds = new HashSet<int>();
foreach (var element in elements)
{
if (!encounteredIds.Contains(element.Id))
{
encounteredIds.Add(element.Id);
}
else
{
return false;
}
}
return true;
}

我使用我的自定义助手,基于ansver:在FluentValidation中检查列表中的属性是否唯一。因为助手比每次描述规则都方便得多。这样的助手可以很容易地与IsEmpty等其他验证器链接。

代码:

public static class FluentValidationHelper
{
public static IRuleBuilder<T, IEnumerable<TSource>> Unique<T, TSource, TResult>(
this IRuleBuilder<T, IEnumerable<TSource>> ruleBuilder,
Func<TSource, TResult> selector, string? message = null)
{
if (selector == null)
throw new ArgumentNullException(nameof(selector), "Cannot pass a null selector.");
ruleBuilder
.Must(x =>
{
var array = x.Select(selector).ToArray();
return array.Count() == array.Distinct().Count();
})
.WithMessage(message ?? "Elements are not unique.");
return ruleBuilder;
}
}

用法:

例如,我们想要选择唯一的id

RuleFor(_ => _.ChildClassCollection!)
.Unique(_ => _.Id);

或者想要选择唯一的id名称

RuleFor(_ => _.ChildClassCollection!)
.Unique(_ => new { _.Id, _.Name });

更新

I使用来自答案YoannaKostova 的代码优化性能

public static class FluentValidationHelper
{

public static bool IsDistinct<TSource, TResult>(this IEnumerable<TSource> elements, Func<TSource, TResult> selector)
{
var hashSet = new HashSet<TResult>();
foreach (var element in elements.Select(selector))
{
if (!hashSet.Contains(element))
hashSet.Add(element);
else
return false;
}
return true;
}

public static IRuleBuilder<T, IEnumerable<TSource>> Unique<T, TSource, TResult>(
this IRuleBuilder<T, IEnumerable<TSource>> ruleBuilder,
Func<TSource, TResult> selector, string? message = null)
{
if (selector == null)
throw new ArgumentNullException(nameof(selector), "Cannot pass a null selector.");
ruleBuilder
.Must(x => x.IsDistinct(selector))
.WithMessage(message ?? "Elements are not unique.");
return ruleBuilder;
}
}

是否只想使用fluentValidator在没有任何关系的情况下实现

如果是这样,您可以自定义一个验证器,然后使用一些逻辑来确认是否存在重复值

在数据库中,如下所示:

public class ChildClassValidator : AbstractValidator<ChildClass>
{
private readonly MyDbContext _context;
public ChildClassValidator(MyDbContext context)
{
_context = context;
RuleFor(x => x.Id).NotEmpty().WithMessage("ID is required.").Must(IsUnique).WithMessage("parent have more than one ids");
}
private bool IsUnique(int id)
{
var model = _context.ParentClasses.GroupBy(x => x.Id)
.Where(g => g.Count() > 1)
.Select(y => y.Key)
.ToList();  //judge whether parentclass has duplicate id
if (model==null) 
return true;
else return false;
}
}

我建议使用下面这样的fluent验证。这样就不会为每个子项迭代相同的集合。

public class ParentValidator : AbstractValidator<ParentClass>
{
public ParentValidator()
{
RuleFor(x => x.ChildClassCollection)
.Cascade(CascadeMode.Stop)
.NotNull()
.NotEmpty()
.Must(x => x.Select(c => c.Id).Distinct().Count() == x.Count());
}
}

相关内容

  • 没有找到相关文章

最新更新