首页 > 解决方案 > Hibernate:添加强制谓词

问题描述

我们在我们的应用程序中引入了一些角色,基于该角色,用户必须访问过滤后的数据。我们已经构建了一个服务,根据用户角色返回必须添加到请求中的谓词。

是否可以以强制和自动的方式将该谓词添加到 Hibernate 将推送到数据库的每个请求中?还是有另一种方法可以为休眠请求提供“强制过滤”?

第一个想法:尝试覆盖实体管理器以添加此行为。

谢谢。

标签: hibernatehibernate-criteria

解决方案


这实际上是不可能的,因为用例是非常特殊的 IMO。很少有所有表都有一组相同的列,您可以对其应用谓词。

您可以尝试org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl#statementPreparer使用执行此操作的自定义实现来覆盖 ,但我认为这样的谓词不适用于您正在执行的所有 SQL。

我不知道这个谓词是什么样的,但是您是否研究过 Hibernate 中的多租户支持?如果您只需要某种tenant = 123谓词,那么使用 Hibernate 很容易。如果您需要更多,则必须以某种方式将此谓词添加到您使用的每个查询中。在 JPQL/HQL 或标准中。

如果谓词的语法类似于 JPQL/HQL,您可以使用Blaze-Persistence,它是一个查询构建器,它接受扩展的 JPQL 变体,支持任意深度路径表达式。这可能如下所示

CriteriaBuilder<Cat> criteriaBuilder = criteriaBuilderFactory.create(entityManager, Cat.class, "cat");
criteriaBuilder.whereExpression("abc > 0 and def = 123"); // Your predicate

如果谓词在不同的抽象级别上,则需要对持久性级别进行某种转换。这就是Blaze-Expression可以帮助您的地方,它是一个开发自定义 DSL 的工具包,可以序列化到 Blaze-Persistence 查询构建器上。

CriteriaBuilder<Cat> criteriaBuilder = criteriaBuilderFactory.create(entityManager, Cat.class, "cat");

// Parse predicate against your context
ExpressionServiceFactory expressionServiceFactory = Expressions.forModel(domain);
ExpressionCompiler compiler = expressionServiceFactory.createCompiler();
ExpressionCompiler.Context context = compiler.createContext(
    Collections.singletonMap("c", domain.getType("CatModel"))
);
Predicate predicate = compiler.createPredicate("abc > 0 and def = 123", context);

// Apply predicate onto the query builder
ExpressionSerializer<WhereBuilder> serializer = expressionServiceFactory.createSerializer(WhereBuilder.class);
ExpressionSerializer.Context context = serializer.createContext(
    Collections.singletonMap("c", "cat")
);
serializer.serializeTo(context, predicate, criteriaBuilder);

推荐阅读