【问题标题】:Should Validation communicate with database?验证应该与数据库通信吗?
【发布时间】:2019-12-07 18:50:12
【问题描述】:

我不确定我是否正确使用了 FluentValidation。我很困惑.. Validator 应该与数据库通信吗?

例如,我有一个端点可以将Item 添加到Order。这是我正在使用的模型和相应的验证器:

public class ItemDto
{
    public int ItemId { get; set; }
    public int OrderId { get; set; }
    public int Quantity { get; set; }
    public int Price { get; set; }
}

public ItemValidator(IItemRepository itemRepository, IOrderRepository orderRepository)
{
    RuleFor(input => input.Price).GreaterThan(0);
    RuleFor(input => input.Quantity).GreaterThan(0);
    RuleFor(input => input.ItemId).Must(name => itemRepository.ItemExists(ItemId))
        .WithMessage(input => $"Item '{input.ItemId}' doesn't exists");
        .Must(name => itemRepository.ItemIsDiscontinued(ItemId))
        .WithMessage(input => $"Item '{input.ItemId}' is discontinued");
    RuleFor(input => input.OrderId).Must(name => orderRepository.OrderExists(OrderId))
        .WithMessage(input => $"Order '{input.OrderId}' doesn't exists");            
}

我想知道,这是应该如何使用验证器吗?

另一种方法是检查Controller 中是否存在特定订单或商品,如果存在则返回NotFound()。然后在验证器中我会检查价格、数量以及该项目是否已停产?

我希望将所有检查和验证集中在一个地方,但是如果 Item 不存在,我将返回 400 状态错误并显示“它不存在”(又名 NotFound)消息。

问题是,我应该将“存在验证”放在 Controller 中,而将其余部分放在 Validator 中吗?如果是,验证器中不应该出现的行到底在哪里?

谢谢,

【问题讨论】:

    标签: c# validation asp.net-web-api asp.net-core-webapi fluentvalidation


    【解决方案1】:

    您可以可靠地通过验证进行多少测试。输入是否有效,只有数据库拥有最终决定权。

    即使您可以测试这些东西,当您实际将数据输入数据库时​​,值可能已经改变。没有可靠的方法对其进行测试。

    诸如外键无效之类的东西?这是Exogenous Exception 的示例。您无法避免外部异常。你必须期待并处理它们。

    【讨论】:

    • 谢谢,只是为了澄清一下:“没有可靠的方法来测试它”是什么意思。在执行插入之前检查它是否存在于数据库中。还有关于外生异常,“你必须期待并处理它们”——但在哪里?在Controller中,Validator还是放手等待处理DB异常?
    • 仅供参考。我已经捕获并处理了所有数据库异常(所以如果发生这样的事件顺序:1. 请求来了;2. 检查是否存在并且它确实 3. 有人删除它;4. 插入记录并抛出异常 - 我处理它)。在验证中,我试图避免它。
    • @IshThomas:“您在执行插入之前检查它是否存在于数据库中”并且在该测试和实际插入之间,现实可能已经改变。可能已添加以前不存在的密钥。以前存在的密钥可能已被删除。与数据库的连接可能已经完成。 |您无法对此进行可靠的测试。
    • 等等..你是说根本不应该有数据库验证?
    • @IshThomas 只有一个相关的验证。 INSERT 期间发生的事件。其规则由 DBMS 维护,基于表上的约束和类似提示。在那之前的一切?您可以使用它来获得舒适感。但很可能只是以它结束了比赛条件:en.wikipedia.org/wiki/Race_condition
    【解决方案2】:

    我的愿景:

    1. 您可以在验证器中使用 db 相关数据

    2. 所有与 db 相关的验证器都应该是瞬态的或作用域的。以HttpContextServiceProviderValidatorFactory 为例

    3. 您可以将验证器拆分为独立于数据库和依赖于数据库。您还可以使用规则或在另一个全局中包含验证器。

    风险:

    • 如果没有 db,您的验证将失败

    • 您应该模拟存储库以进行测试

    示例: https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation/blob/master/samples/SampleWebApi/Validators/BlogValidator.cs

    【讨论】:

    • "如果没有 db,您的验证将失败" - 我可以创建一个 BaseDbValidator 类来验证数据库是否可用。然后每个将连接到数据库的验证器都将从该验证器继承。因此,如果您向 API 发送请求,API 会告诉您 DB 不可用
    猜你喜欢
    • 2018-12-29
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-13
    • 2016-07-21
    相关资源
    最近更新 更多