Reputation: 16320
I have these 2 classes:
public class Master
{
public int? TotalAmount;
public ICollection<Detail> Details;
}
public class Detail
{
public int Amount;
}
I'm trying to create a rule so that the details collection's total amount is equal to the master's total amount property.
I'm trying the following rule but I can't access the master's property:
RuleFor(x => x.Details)
.Must(coll => coll.Sum(item => item.Amount) == x.TotalAmount)
.When(x => x.Details != null)
.When(x => x.TotalAmount.HasValue);
What is the correct way to implement this kind of rule?
Upvotes: 2
Views: 532
Reputation: 101543
You can just use another overload of Must, like this:
RuleFor(x => x.Details)
.Must((master, details, ctx) => master.TotalAmount == details.Sum(r => r.Amount))
.When(x => x.Details != null)
.When(x => x.TotalAmount.HasValue);
However note that, as already pointed in comments, you should not use validation for consistency checks. You just have one piece of data (sum of details amount). So why just not do like this:
public class Master {
public int? TotalAmount
{
get
{
if (Details == null)
return null;
return Details.Sum(c => c.Amount);
}
}
public ICollection<Detail> Details;
}
Upvotes: 2
Reputation:
The best way I have found to achieve this type of validation is to use a custom validator method like the following:
public class Validator : AbstractValidator<Master>
{
public Validator()
{
RuleFor(master => master)
.Must(CalculateSumCorrectly)
.When(master => master.Details != null)
.When(master => master.TotalAmount.HasValue);
}
private bool CalculateSumCorrectly(Master arg)
{
return arg.TotalAmount == arg.Details.Sum(detail => detail.Amount);
}
}
Notice that the rule here is being described as applying to the entire master object; RuleFor(master => master)
. This is the trick that allows you to access both properties.
Upvotes: 0