如何在Spring Data JPA中为所有查询创建动态WHERE子句?

3

我有这样一个需求,需要动态地将全局的 WHERE 条件传递给所有查询?

我们有多个组织的表格数据,因此在检索数据时需要传递 ORG_ID = ?

我不想编写像 findBy..AndOrgId(... Integer orgId) 这样的查找方法。有更好的方法吗?可以应用全局 WHERE 子句或 Predicate 吗?

我将在 RestController 中的请求属性中接收到这个 orgId 参数。由于它是动态的,因此无法在实体类上使用 hibernate 注释 @Where


@SternK 不应该从帖子中删除对Spring Data的引用。 - Saud
1
我没有做这件事。请查看此链接。文章标题对于技术名称来说不太合适。 - SternK
1
@SternK Spring Data 可能出现在标题的最后。例如,检查一个被接受的答案的假设。 - v.ladynev
谢谢。我已经将它添加到标题的末尾。 - Saud
请返回已翻译的文本。 - luiscla27
3个回答

4
您可以尝试使用Hibernate的@Filter注解。如文档所述:(文献)

@Filter注释是使用自定义SQL条件过滤实体或集合的另一种方法。与@Where注释不同,@Filter允许您在运行时参数化过滤器子句。

示例1:

import org.hibernate.annotations.Filter;
import org.hibernate.annotations.FilterDef;
import org.hibernate.annotations.ParamDef;

@Entity
@Table(name = "MY_ORDER")
@FilterDef(
   name="byId",
   parameters = @ParamDef(
      name="ordId",
      type="long"
   )
)
@Filter(
   name="byId",
   condition="ord_id = :ordId"
)
public class MyOrder
{
   @Id
   @Column(name = "ord_id")
   private Long id;

   // ...
}

及其使用:

EntityManager em = emFactory.createEntityManager();
// ...
em.unwrap(Session.class).enableFilter("byId").setParameter("ordId", 2L);

List<MyOrder> orders = em.createQuery("select o from MyOrder o", MyOrder.class)
   .getResultList();

以下 SQL 将被生成:
/* select o from MyOrder o */
select
  myorder0_.ord_id as ord_id1_3_,
  myorder0_.ord_time as ord_time2_3_ 
from TEST_SCHEMA.MY_ORDER myorder0_ 
where myorder0_.ord_id = ?

编辑

上述描述的方法同样适用于使用spring data jpa @Query 和从方法名称派生的查询。

示例2:

@Entity
@Table(name = "post")
@FilterDef(
   name="postById",
      parameters = @ParamDef(
         name="postId",
         type="long"
      )
   )
@Filter(
   name="postById",
   condition="id = :postId"
)
public class Post
{
   @Id
   private Long id;

   @Enumerated(EnumType.ORDINAL)
   private PostStatus status;

   // getters, setters
}

public enum PostStatus { OPEN, CLOSE }

public interface PostRepository extends JpaRepository<Post, Long>
{
   @Query(value = "select p from Post p where p.status = :sts")
   List<Post> test(@Param("sts") PostStatus status);

   List<Post> findByStatus(PostStatus status);
}

@RestController
public class TestRestController
{
   @Autowired
   EntityManager entityManager;

   @Autowired
   private PostRepository postRepository;

   @RequestMapping("/")
   @Transactional
   public String home()
   {
      entityManager
          .unwrap(Session.class)
          .enableFilter("postById")
          .setParameter("postId", 10L);
       // ....
       List<Post> posts1 = postRepository.test(PostStatus.OPEN);
       List<Post> posts2 = postRepository.findByStatus(PostStatus.OPEN);
   }      
}

我喜欢使用@Filter的想法,有没有办法在存储库中使用@Query - Eklavya

1

我假设你使用基于Spring Data的标签 (based on your post tags),它目前不支持查询增强。 这里有一个长期以来请求该功能的链接,其中还描述了一些其他人尝试过的替代方案。

祝好运!


谢谢。是的,我正在寻找基于spring-data-jpa的解决方案。 - Saud

0

我需要加载所有实体,映射有所帮助

@Entity
@Where(clause = "is_active = true")
data class Account(
    @Column(unique = true, nullable = false)
    var phone: String,
    @Embedded
    val name: Name,
    @Column(nullable = false)
    var password: String,
    @ManyToOne(fetch = FetchType.EAGER)
    var role: Role,
    var isActive: Boolean
){
    @Id
    var id: Long = 0

    @CreationTimestamp
    var dateCreated: Timestamp? = null

    @UpdateTimestamp
    var dateUpdated: Timestamp? = null
}

创建相同的实体并映射它。
@Entity
@Immutable
@Subselect("select * from account")
data class AccountWithRemove(
    @Column(unique = true, nullable = false)
    var phone: String,
    @Embedded
    val name: Name,
    @Column(nullable = false)
    var password: String,
    @ManyToOne(fetch = FetchType.EAGER)
    var role: Role,
    var isActive: Boolean,
    var code: Long?
) {
    @Id
    var id: Long = 0

    @CreationTimestamp
    var dateCreated: Timestamp? = null

    @UpdateTimestamp
    var dateUpdated: Timestamp? = null
}

这就是带规格的请求的样子。搜索常规和已删除的账户。

from
        ( select
            * 
        from
            account ) accountwit0_ 
    where
        accountwit0_.is_active=true 
        or accountwit0_.is_active=false 

这是一个正常的findAll()查询

from
        ( select
            * 
        from
            account ) accountwit0_

Hibernate不会创建新表,我们只需创建一个新实体并映射其中不需要@Where注解的实体。 我删除了一些字段,但我认为意思是清楚的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接