如何根据子属性选择父对象和顺序

时间:2014-09-29 14:08:30

标签: java sql hibernate jpa

免责声明:我们的数据库是遗产,并不完全理想。我正在尝试解决JPA映射问题以处理非理想的数据库,这超出了我的工作范围。请不要DB设计评论...

我必须做两件事。我必须获取一个父项及其子项,给定一个子项的属性匹配,我必须按子项的属性对返回的对象进行排序。

我想知道我是否可以使用“获取加入”来代替常规连接。

类/映射基本上如下所示:

@Entity
@Table(name = "profiles")
public class Profile  {
    @Id
    private Long id;

    @OneToMany(mappedBy = "profile", fetch = FetchType.LAZY)
    // @Where(clause = "deleted is null or deleted = 'N'")     (1)
    private List<Account> accounts;

    <...snip...>
}

@Entity
@Table(name = "accounts")
public class Account {
    @Id
    private Long id;

    @ManyToOne
    @JoinColumn(name = "profile_id", nullable = false, insertable = true, updatable = false)
    private Profile profile;

    private String name;

    <...snip...>
}

基本上我想要的SQL是这样的:

select p.*, a.*
from profiles p, accounts a
where a.profile_id = p.id and lower(a.name) like '%some_search_text%'
order by lower(a.name);

问题是构建一个JPA查询,如:

String searchText = "%foobar%";

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Profile> criteriaQuery = criteriaBuilder.createQuery(Profile.class);
Root<Profile> profile = criteriaQuery.from(Profile.class);
Join<Profile, Account> profileAccountJoin = profile.join(Profile_.accounts);

criteriaQuery.where(
    criteriaBuilder.like(
        criteriaBuilder.lower(profileAccountJoin.get(column).as(String.class)), searchText);

criteriaQuery.orderBy(profileAccountJoin.get(Account_.name)); // ??? this maybe works

TypedQuery<Profile> query = entityManager.createQuery(criteriaQuery);

List<Profile> results = query.getResultList();

我会得到一个孩子匹配的个人资料列表。但是后来当转换为DTO并执行profile.getAccounts()时,我将获得profile_id上​​匹配的所有帐户,而不是按名称过滤。

如何在JPA中实现此行为,特别是上面的示例SQL查询?

如果我能够或应该使用“获取加入”来完成此操作,我将如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

当您添加hibernate标记时,我想知道您是否乐意使用特定于Hibernate的注释Filter。您可以在Account上定义一个过滤器,用于过滤与个人资料相关联的帐户。这可能是你如何做到的: 在帐户中:

Profile

然后在个人资料中:

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

@Entity
@FilterDef(name = "myFilter", parameters = @ParamDef(name = "nameParameter", type = "string"))
@Table(name = "accounts")
public class Account {
...

最后,您需要为会话启用过滤器:

@OneToMany(mappedBy = "profile", fetch = FetchType.LAZY)
@Filter(name = "myFilter", condition = ":nameParameter = name")
private List<Account> accounts;

public List<Account> getAccounts() {
    return accounts;
}

这是我对如何做到这一点的猜测。也许它会鼓励有人改进它。有关http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#objectstate-filters

过滤器的文档