2014-09-29 49 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