2014-09-29 53 views
0

免责声明:我们的数据库是遗留的,并不完全理想。我试图解决JPA映射问题来处理超出我的工作范围的非理想DB。请不要DB设计评论...如何选择父母对象并按孩子的属性排序

我必须做2件事。我必须获取一个父项及其子项,只要匹配其中一个子项的属性,并且必须通过该子项的属性来排序返回的对象。

我想知道如果我可以使用“获取联接”来做到这一点,而不是常规联接。

的类/映射基本上是这样的:

@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,而不是按名称进行过滤。

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

如果我可以或应该使用'fetch join'来做这件事,我会怎么做呢?

回答

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; 
} 

最后,你需要让你的会话过滤器:

Session session = ...; 
    session.enableFilter("myFilter").setParameter("nameParameter", "Geordi La Forge"); 
    Profile profile = ...; 
    List<Account> geordiAccounts=profile.getAccounts(); 

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

+0

谢谢。这应该工作。是的,我实际上并没有看到我们改变了我们的JPA实施。 – lostdorje 2014-10-03 05:47:07