如何有效地验证数据库或任何外部数据源的ID集合?

时间:2016-07-19 18:41:18

标签: c# fluentvalidation

我有一个服务,它将ProcessOrdersArgs作为参数,可以包含数千个Order对象。我需要针对数据库服务器验证传入的每个订单是否是存在的实际有效订单。现在,对于处理数千个订单的单个服务调用,我只是为了验证传入的订单而进行了数千次往返数据库的访问,并且我希望显着减少用于验证的数据库往返次数。

我的验证有以下相关课程。我的OrderValidator中的.CustomerId和.OrderId是FluentValidation PropertyValidator类的扩展。

CustomerIdValidator内置了缓存,因为通常会处理数千个订单,其中许多是针对同一个客户的,我希望在验证同一个CustomerId时减少到数据库的往返。

我想用OrderIds做类似的事情并限制数据库往返次数,但缓存不是解决方案,因为可能的千位数的每个OrderId都是唯一的。我想批量验证这些OrderIds。我的想法是批量复制每个客户端的OrderIds列表,并返回无效OrderIds列表(如果有)以报告为验证错误。

我该怎么做,还是有另外一种方法来构建我的验证,以便我可以批量验证订单而不是进行数千次往返数据库调用?

public class Order
{
    public int CustomerId { get; set; }
    public int OrderId { get; set; }
}

public class ProcessOrdersArgs
{
    public List<Order> Orders { get; set; }
}

public class ProcessOrdersArgsValidator : AbstractValidator<ProcessOrdersArgs>
{
    public ProcessOrdersArgsValidator(OrderValidator orderValidator)
    {
        RuleFor(a => a.Orders)
            .SetCollectionValidator(orderValidator);
    }
}

public class OrderValidator : AbstractValidator<Order>
{
    public OrderValidator(DBConnection dbConnection)
    {
        RuleFor(c => c.CustomerId)
            .CustomerId(dbConnection);

        RuleFor(c => c.OrderId)
            .OrderId(dbConnection, c => c.CustomerId);
    }
}

1 个答案:

答案 0 :(得分:1)

您可以将predicate validator MustMustAsync用于Orders属性

public class ProcessOrdersArgsValidator : AbstractValidator<ProcessOrdersArgs>
{
    public ProcessOrdersArgsValidator(DBConnection dbConnection)
    {
        RuleFor(a => a.Orders).Must(orders =>
        {
            var ids = orders.Select(o => o.OrderId);

            return BulkValidateIds(ids, dbConnection);
        });
    }

    private bool BulkValidateIds(IEnumerable<int> ids, DBConnection dbConnection)
    ....
}