2011-06-12 3 views
2

을 사용하여 in-statement의 오른쪽 부분을 검색하는 데 필요한 Subselect 이제 JPA 및 기타 Java EE 6 관련 자료를 가지고 놀고 있지만 기준 빌더를 사용하는 유형 쿼리에 문제가 있습니다. 내 poc에 대한 비즈니스 사례는 트위터 복제품이므로 구독자 및 구독 목록이있는 사용자가 있으며 트윗이 있습니다. 트윗 TwitterUser 및 TwitterUser_TwitterUser : JPA 의해 생성CriteriaBuilder (JPA)

@Entity 
public class Tweet { 
    @Id @GeneratedValue(strategy=GenerationType.AUTO) 
    private Long id; 

    @ManyToOne 
    private TwitterUser author; 

    @ManyToOne 
    private TwitterUser receiver; 

    @Temporal(TemporalType.TIMESTAMP) 
    private Date datetime; 

    private String message; 
} 


@Entity 
public class TwitterUser { 
    @Id @GeneratedValue(strategy=GenerationType.AUTO) 
    private Long id; 

    private String username; 

    private String displayname; 

    private String password; 

    private String email; 

    @Temporal(TemporalType.TIMESTAMP) 
    private Date since; 

    @ManyToMany(cascade=CascadeType.ALL) 
    private List<TwitterUser> subscriptions; 

    @ManyToMany(mappedBy = "subscriptions") 
    private List<TwitterUser> subscribers; 
} 

데이터 모델은 3 개의 테이블로 구성되어있다. 지금까지는 괜찮습니다. 기본 쿼리가 제대로 작동합니다.

타임 라인에 대한 모든 트윗을 선택하고 싶습니다. 현재 로그인 한 사용자의 가입 목록에있는 모든 트윗을 의미합니다.

select * from TWEET where author_id in (
    select subscriptions_ID from TWITTERUSER_TWITTERUSER where subscribers_ID = ?loggedInUserId); 

이 쿼리는 잘 작동하지만, 나는 CriteriaBuilder과 제네릭을 사용하여 아래로 작성하는 방법에 대해 아무 생각이 : 나는 부속을 사용하여 솔루션의 생각과 같이 내 SQL은 보일 것이다. 하위 쿼리의 형식이 무엇인지 확신 할 수 없기 때문에 다른 지점에서 오류가 발생할 수있는 컴파일 가능한 코드 조각도 얻지 못합니다. 지금 많은 예제를 통해 검색 중이지만 대부분은 원시 유형을 사용하거나 in-clause의 왼쪽면 요소를 검색하기 위해 하위 쿼리를 사용합니다.

어쩌면 나는 나무가 부족한 나무를 그리워 할 지 모르지만 나는 정말로 당혹 스럽다. :(

JPQL에서

답변

1

그래서 감사

http://en.wikibooks.org/wiki/Java_Persistence/Querying#Subselect.2C_querying_all_of_a_ManyToMany_relationship는. 나는 마지막으로 관리 귀하의 의견과 해결책을 찾아 내고 보이는 다음과 같이

public List<Tweet> findAllForSubscriber(TwitterUser user) { 
    // Select tweets 
    CriteriaBuilder cb = em.getCriteriaBuilder(); 
    CriteriaQuery<Tweet> cq = cb.createQuery(Tweet.class); 
    Root<Tweet> tweet = cq.from(Tweet.class); 
    cq.select(Tweet); 

    // Select subscribers of user 
    Subquery<Long> sq = cq.subquery(Long.class); 
    Root<TwitterUser> twitterUser = sq.from(TwitterUser.class); 
    Join<TwitterUser, TwitterUser> subscriptions = twitterUser.join(TwitterUser_.subscriptions); 
    sq.select(subscriptions.get(TwitterUser_.id)); 
    sq.where(cb.equal(twitterUser, user)); 

    // Where authorId in list of subscribers 
    cq.where(cb.in(tweet.get(Tweet_.author).get(TwitterUser_.id)).value(sq)); 

    // 
    return em.createQuery(cq).getResultList(); 
} 

내 단점이 있었다 :

  • 기준 API는 동일한 내에서 객체의 비교를 할 단지 수()하지만 in() 문 내에서 하지만이 도움이 예외를하지 않았다, 가 생성 된 모든는 잘못된 쿼리 (EclipseLink가 & 더비 경기가) :(
  • 가에서() 문 가 문에서의 왼손 측 소요
  • , 값 문이 걸립니다이었다 가능성의 목록은 표현은 테이블 구조에 대한 생각한다면 그것은 매우 분명하다. 나는 단순히 내가 조인을 사용할 필요는 IDS 모든 구독 에 액세스 할 수 없습니다.
  • 나를 혼동하지만 는 것을 놓쳤다 단순히 내 생각이 일 때.

P.S. : 내 솔루션이 사용자 자신의 트윗을 완전히 선택하지 못했습니다!^^

3

,이 다음에 가깝다 뭔가 될 것 표현하는 하나 개의 방법 : 거의 직접 JPQL 모델 다음

SELECT 
    tweet 
FROM 
    Tweet tweet JOIN tweet.author author 
WHERE 
    EXISTS (
     SELECT 
       user 
     FROM 
       TwitterUser user JOIN user.subscriptions subscriber 
     WHERE 
       user = :loggedinUser AND 
       subscriber = author 
    ) 

으로 CRITERIAS는, 어쩌면 이것은 당신이 시작 도착

+0

안녕하세요 Arjan, 제안을 주셔서 감사합니다. 문제를 다시 생각해 보았습니다. 타임 라인을 표시하려는 사용자의 모든 구독자 목록이 이미 있음을 알고 있기 때문에 매우 쉬운 해결책을 발견했습니다. 정말 고마워요.하지만 마침내 제가 미치게 만드는 원인은 QueryBuilder로 내 쿼리를 작성하는 방법을 찾지 못했기 때문입니다. 그러나 잘, 나는 너의 것을 공식화 할 수 없었다! ^^ 그래서 나는 표현에 대한 나의 이해를 위해 노력해야한다고 생각합니다. – Patrick

+0

일반적으로 JPQL (및 Criterias와 함께)은 SQL의 정신을 따릅니다. 그러나 JPQL은 연관 (연결) 테이블을 노출시키지 않으므로 임의의 테이블에서 임의의 열을 결합 할 수 없기 때문에 때때로 접근 방식에 대한 생각을 바꾸어야합니다. –

+1

흥미로운 것은 내 문제에 대한 해결책을 얻지 못했기 때문에 Criteria API를 사용하는 방법을 알고 싶었 기 때문에 Criteria API를 사용하여이를 수행하는 방법을 알고 싶었습니다. 참여를 사용하는 접근법은 내가 놓친 사실 중 하나 였고, 올바른 해결책을 찾는데 도움이되었습니다. 감사합니다! :) – Patrick

0

이있다. 저를 도와 여기에 유사한 기준 쿼리 예를 들어, 너희들을 다시

+0

링크를 보내 주셔서 감사합니다. 마침내 입력 된 검색어가 입력되지 않은 검색어로 바뀌 었습니다. 그러나 그것은 단순히 in() 문을 잘못 사용했다는 것을 보여주었습니다. 다시 한 번 감사드립니다 :) – Patrick