【问题标题】:How to use Hibernate Validator to validate date ranges across multiple rows in a table?如何使用 Hibernate Validator 验证表中多行的日期范围?
【发布时间】:2017-12-21 16:42:17
【问题描述】:

我有一个自定义验证器,用于确保在保存实体之前将某些业务规则应用于实体。

例如(假设一个),当保存下面定义的 ProductPrice 时,我验证给定产品(由 productId 标识)的 fromDate 和 endDate 与现有的 ProductPrice 行没有重叠数据库中的产品。

@MyCustomValidator
class ProductPrice {

  Long productId;

  Date fromDate;
  Date toDate; 
}

只要将ProductPrice 保存为单独的实体,它就可以正常工作。一旦将该实体作为一对多关系添加到另一个实体中,如下所示,

class Product {
  List<ProductPrice> productPrices;
}

当父(产品)实体更新(保存它工作正常),以及子实体中的一些更改(列表中的一个或多个 ProductPrice)时,它会因为保存 ProductPrice 的一个实例而失败List 不知道接下来要保存的 ProductPrice 的任何信息。

详细解释:

假设对于给定的Product,DB 中有两个ProducePrice 行,如下所示:

Id    Product Id        From Date        To Date        Price
1     PRD-001           01-01-2016       10-06-106      29.99
2     PRD-001           11-06-2016       10-12-106      32.99

假设我想将作为Product 实体一部分的两行 (ProductPrice) 更新为以下值:

Id    Product Id        From Date        To Date        Price
1     PRD-001           01-01-2016       30-06-106      29.99
2     PRD-001           01-07-2016       31-12-106      32.99

以上数据仍然有效,但是hibernate验证器会失败。那是因为当我查询数据库以检查现有行的fromDatetoDate 时,保存第一行时,它将与数据库中存在的第二行重叠。但这是不正确的,因为第二行也将使用有效值进行更新。也有可能,表中有 3 行,而我在当前事务中只更新了其中的 2 行,第 3 行没有被触及。所以重要的是我必须在验证器中查询数据库以检查有效性。

问题太长,我可能无法清楚地解释问题。但是总结一下,是否可以查询当前的持久化上下文,得到脏的(即将被保存)的数据?

【问题讨论】:

    标签: java hibernate validation bean-validation hibernate-validator


    【解决方案1】:

    它可以工作,但我不确定它的优化程度,这取决于您的上下文。

    但想法是,当您查询数据库以检查现有行的 fromDate 和 toDate 时,您还应该查询您将从中更新数据库的集合,并在此基础上更新 fromDate 和 toDate,在这种情况下将是有效:)

    【讨论】:

    • 验证器一次只能从集合中获取一个条目,它对集合本身一无所知。我希望这很容易,只是比较查询结果和集合的组合:-)
    【解决方案2】:

    考虑将验证器放在Product 实体上,而不是ProductPrice

    @ProductPricesCheck
    class Product {
      List<ProductPrice> productPrices;
    }
    

    ...验证器看起来像这样:

    class ProductPricesValidator implements ConstraintValidator<ProductPricesCheck, Product> {
      @Override
      public boolean isValid(final Product product, final ConstraintValidatorContext context) {
        for (ProductPrice productPrice : product.getProductPrices()) {
          // Insert logic for checking the date ranges don't overlap here...
          // ...Return true or false as appropriate.
        }
      }
    }
    

    【讨论】:

    • 这是我想到的一个选项,但是如果我独立更新 ProductPrice(不是作为 Product 的一部分),那么验证器将不会被触发。
    • 那么也许有两个验证器?如果您可以发布您的 ProductPrice 验证器的现有代码,这可能会有所帮助,因为我不确定它目前是如何工作的。
    • 如果我有两个验证器,那么当验证器为 ProductPrice 运行时,将遇到问题中提到的我正试图避免的问题。我目前拥有的验证器与您在答案中提到的完全相同,只是它适用于 ProductPrice 而不是 Product。
    • 不确定您是如何查询以获取其他 ProductPrices 但这可能是相关的:stackoverflow.com/questions/9908061
    • 查询ProductPrice 不是问题,因为我在单独的事务中查询验证者的事务。
    【解决方案3】:

    你应该使用@Valid注解

    class Product {
    
      @Valid
      List<ProductPrice> productPrices;
    }
    

    查看link了解更多信息

    【讨论】:

      猜你喜欢
      • 2017-11-06
      • 1970-01-01
      • 1970-01-01
      • 2020-04-03
      • 2022-10-14
      • 1970-01-01
      • 2013-10-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多