FluentValidation 检查子集合中的重复实体
FluentValidation checking for duplicate entity in a sub-collection
我有一个 MainEntity
class 并且它有一个集合 SubEntity
。以下为当前验证:
public class MainEntityValidator : AbstractValidator<MainEntity>
{
public MainEntityValidator()
{
RuleFor(x => x.SubEntities).SetCollectionValidator(new SubEntityValidator());
}
public class SubEntityValidator : AbstractValidator<SubEntity>
{
public SubEntityValidator()
{
RuleFor(x => x.Field1).NotNull();
RuleFor(x => x.Field2).NotNull();
}
}
}
如何添加验证规则,以便只有唯一的 SubEntity
个对象(基于 Field1
和 Field2
)必须在集合中?
我想您问题的答案是将 collection 中的每个项目与其他每个项目进行比较,并在 objects 为 "equal" 时验证失败。如果您的 collection 包含的项目数量不多,我不建议这样做。更好的方法是实施 Equals() 和 GetHashCode(),以便基础 class 库中的 collection 类型可以预测地处理您的 SubEntity objects。我会 post 举个例子,但我不知道你的 objects 是什么样子,因为你还没有 post 编辑它们。无论如何,如果您以有意义的方式实现这些方法,您可以将 collection 定义为已经具有适当的唯一约束的类型(例如 T 的 HashSet)。
如果您需要将验证规则应用于集合 属性 但仍需要访问主模型和(或)整个集合,而不仅仅是要验证的项目,那么 RuleForEach
方法是您的选择:
var comparer = new SubEntityComparer();
RuleForEach(x => x.SubEntities)
.Must((model, submodel) => model.SubEntities.Count(xsub => comparer.Equals(xsub, submodel)) == 1) // one match that ReferenceEquals hit
.WithMessage("The item with values {0}, {1} has duplicates in collection of {2} items",
(model, submodel) => submodel.Field1,
(model, submodel) => submodel.Field2,
(model, submodel) => model.SubEntities.Count); // in validation message generation you can access to current item as well as to main model
如果您描述的验证规则只需要一条错误消息 — 您可以将简单谓词规则应用于集合 属性 SubEntites
:
RuleFor(x => x.SubEntities)
.Must(coll => coll.Distinct(new SubEntityComparer()).Count() == coll.Count)
.WithMessage("One or more items in collection of {0} items are duplicates",
(model, coll) => coll.Count); // has access to collection and to main model
在这两种情况下,我都使用了相同的相等比较器,但您也可以覆盖 Equals
方法,并使用 IEnumerable
扩展方法的重载和重载,排除 EqualityComparer
参数.
下面列出的 EqualityComparer 代码:
public class SubEntityComparer : IEqualityComparer<SubEntity>
{
public bool Equals(SubEntity x, SubEntity y)
{
if (x == null ^ y == null)
return false;
if (ReferenceEquals(x, y))
return true;
// your equality comparison logic goes here:
return x.Field1 == y.Field1 &&
x.Field2 == y.Field2;
}
public int GetHashCode(SubEntity obj)
{
return obj.Field1.GetHashCode() + 37 * obj.Field2.GetHashCode();
}
}
更新:
在这两种实现集合验证的方法中,您仍然可以使用 SetCollectionValidator(new SubEntityValidator())
通过简单的规则独立验证每个项目。
我有一个 MainEntity
class 并且它有一个集合 SubEntity
。以下为当前验证:
public class MainEntityValidator : AbstractValidator<MainEntity>
{
public MainEntityValidator()
{
RuleFor(x => x.SubEntities).SetCollectionValidator(new SubEntityValidator());
}
public class SubEntityValidator : AbstractValidator<SubEntity>
{
public SubEntityValidator()
{
RuleFor(x => x.Field1).NotNull();
RuleFor(x => x.Field2).NotNull();
}
}
}
如何添加验证规则,以便只有唯一的 SubEntity
个对象(基于 Field1
和 Field2
)必须在集合中?
我想您问题的答案是将 collection 中的每个项目与其他每个项目进行比较,并在 objects 为 "equal" 时验证失败。如果您的 collection 包含的项目数量不多,我不建议这样做。更好的方法是实施 Equals() 和 GetHashCode(),以便基础 class 库中的 collection 类型可以预测地处理您的 SubEntity objects。我会 post 举个例子,但我不知道你的 objects 是什么样子,因为你还没有 post 编辑它们。无论如何,如果您以有意义的方式实现这些方法,您可以将 collection 定义为已经具有适当的唯一约束的类型(例如 T 的 HashSet)。
如果您需要将验证规则应用于集合 属性 但仍需要访问主模型和(或)整个集合,而不仅仅是要验证的项目,那么 RuleForEach
方法是您的选择:
var comparer = new SubEntityComparer();
RuleForEach(x => x.SubEntities)
.Must((model, submodel) => model.SubEntities.Count(xsub => comparer.Equals(xsub, submodel)) == 1) // one match that ReferenceEquals hit
.WithMessage("The item with values {0}, {1} has duplicates in collection of {2} items",
(model, submodel) => submodel.Field1,
(model, submodel) => submodel.Field2,
(model, submodel) => model.SubEntities.Count); // in validation message generation you can access to current item as well as to main model
如果您描述的验证规则只需要一条错误消息 — 您可以将简单谓词规则应用于集合 属性 SubEntites
:
RuleFor(x => x.SubEntities)
.Must(coll => coll.Distinct(new SubEntityComparer()).Count() == coll.Count)
.WithMessage("One or more items in collection of {0} items are duplicates",
(model, coll) => coll.Count); // has access to collection and to main model
在这两种情况下,我都使用了相同的相等比较器,但您也可以覆盖 Equals
方法,并使用 IEnumerable
扩展方法的重载和重载,排除 EqualityComparer
参数.
下面列出的 EqualityComparer 代码:
public class SubEntityComparer : IEqualityComparer<SubEntity>
{
public bool Equals(SubEntity x, SubEntity y)
{
if (x == null ^ y == null)
return false;
if (ReferenceEquals(x, y))
return true;
// your equality comparison logic goes here:
return x.Field1 == y.Field1 &&
x.Field2 == y.Field2;
}
public int GetHashCode(SubEntity obj)
{
return obj.Field1.GetHashCode() + 37 * obj.Field2.GetHashCode();
}
}
更新:
在这两种实现集合验证的方法中,您仍然可以使用 SetCollectionValidator(new SubEntityValidator())
通过简单的规则独立验证每个项目。