2010-01-09 2 views
5

테이블 A의 엔터티를 선택하기 위해 두 번째 테이블 B를 조인하는 조건 쿼리가 있습니다.이 쿼리는 테이블 A의 여러 엔터티를 반환합니다. 타임스. 하지만 결과가 뚜렷해야합니다.투영하지 않고 최대 절전 기준 - 쿼리에 그룹 추가

SQL-Query를 실행 한 후 여러 건의 발생을 필터링하므로 Criteria.DISTINCT_ROOT_ENTITY를 사용하면 쓸모가 없습니다. 따라서 검색 결과를 20 개로 제한하면 내 쿼리와 일치하는 항목이 더 많지만 4 개로 끝납니다.

순수 SQL에서는 단순히 테이블 A의 엔터티를 선택하기 위해 테이블 ​​B의 조인 만 사용되기 때문에 "GROUP BY ID"를 쿼리에 추가 할 수 있습니다. 그러나 Criteria-API I 이럴 수는 없어. "GROUP BY"를 추가하는 유일한 방법은 Projections를 사용하는 것입니다. 그러나 그때, 나는 스칼라 값으로 끝나고, 실제 클래스의 인스턴스로 끝나지 않습니다. hibernate가 "GROUP BY"절 뒤에 잘못된 "1 = 1"을 추가하기 때문에 SQL 제한 사용은 작동하지 않습니다. :(

어떤 아이디어?

+0

'GROUP BY'는 정의상 데이터의 집계를 포함하므로 투영이 필요합니다. 테이블의 더 자세한 정보와 Hibernate가 생성하기를 원하는 SQL 질의를 추가했다면, 우리는 더 잘 권고 할 수있다. – skaffman

+0

클래스 이벤트가 있습니다. 이 클래스에는 날짜 목록이 있습니다. (사실이 날짜들은 특수 클래스 인 DateWrapper로 Date를 감싸고 Id를 추가합니다. 왜냐하면 최대 절전 모드가 바로 값 유형의 콜렉션을 결합 할 수 없기 때문입니다). 나는 이벤트를 쿼리하고 x와 y 사이에 하나 이상의 이벤트가있는 모든 이벤트를 찾고 싶다. Criteria-API에 의해 생성되고 "GROUP BY id"를 추가 한 SQL-Query를 grap하면 정확하게 찾고있는 것입니다. 그러나 나는 GROUP BY를 추가하기 위해 Hibernate를 주장 할 방법을 찾을 수 없다! –

답변

0

Hibernate는 개체를 반환하는 데 사용할 수있는 실제 SQL 쿼리를 작성할 수 있습니다. 당신이 정말로, 당신은 HQL을 무시하고 당신이 당신의 그룹과 정확히 원하는 쿼리를 작성할 수 있습니다해야하는 경우 그래서 . 그것에 의해

자세한 내용은 here를 참조

를 예를 들어 당신이 당신의 hbm.xml 파일에서이 같은 쿼리 뭔가를 정의 할 수 있습니다.

<sql-query name="exampleQuery"> 
<query-param name="param" type="int"/> 
<return alias="x" class="foo.bar.X"/> 
<return alias="y" class="foo.bar.Y"/> 
    <![CDATA[ 
     select {x.*}, {y.*} 
     from XEntity x 
     inner join YEntity y on y.xId = x.id 
     where y.value = :param 
    ]]> 
</sql-query> 
,

{x. } 및 {y.} 엔티티 X와 엔티티 Y의 모든 속성을 선택하는 약식 구문

+0

답변 해 주셔서 감사합니다 :) 그러나 나는 HQL을 사용하지 않고 있습니다. 쿼리를 동적으로 컴파일해야하기 때문에 Criteria-API를 사용하고 있습니다. 그래서, 나는 스칼라 값이 아닌 리졸 빙 (reslut)으로 클래스의 실제 인스턴스가 필요하기 때문에, Projections을 사용하지 않고 Hibernate가 id 속성으로 결과를 그룹화하도록 지시 할 방법을 찾아야한다. –

+0

위와 같이 명명 된 쿼리가 아닌 프로그래밍 방식으로 원시 SQL 쿼리를 지정할 수도 있습니다 (기준 API를 사용하지 않아도 가능). – alasdairg

1

이런 식으로 사용하려고 했습니까?

 ICriteria criteria = dc.GetExecutableCriteria(RepositoryInstance.Session) 
           .SetProjection(
            Projections.Distinct(Projections.ProjectionList() 
             .Add(Projections.Property("Prop1"),"Prop1") 
             .Add(Projections.Property("Prop2"),"Prop2") 
             .Add(Projections.Property("Prop3"),"Prop3") 
             .Add(Projections.Property("Prop4"),"Prop4"))); 
result = criteria.List(); 

클래스를 반사하여 속성을 동적으로 추가 할 수 있습니다.

이이 같은 SQL 생성 : 그 관계가 있기 때문에 내가 DetachedCriteria dc을 포함하지 않았다 select distinct prop1,prop2,prop3,prop4 from yourClass

합니다.

1

투영되지 않고 그룹 : 대부분의 사람들은 볼 수 있습니다. 그러나 대부분의 사람들은 프로젝션을 사용하고 싶지 않습니다. 콩을 투영해야한다는 것입니다. (그리고 결과로 리턴됩니다). 아래 예제에서 나는 project을 시도했는데 결과물로는 bean이 필요합니다.

저는 약간의 트릭으로 같은 결과를 얻었습니다. 먼저 프로젝션없이 그룹을 적용하려고했지만 솔루션을 찾지 못했기 때문에 프로젝션에 의존해야합니다.여기

내가 내 엔티티 빈입니다 Parent 클래스로 p.*를 원하고 나는 그것이 고유 원 자바 코드에서

select p.* FROM parent p INNER JOIN child c ON p.id_parent=c.id_father 
WHERE c.child_name like '%?%' AND p.parent_name like '%?%' 
group by p.id_parent 

을 달성하고 싶었다 무엇 하나의 방법은에 결과 목록을 얻을 수있다 설정,하지만 난 여러 가지 이유로 이런 식으로하지 말아요 :)

그래서 Parent.class 대신 Child.class에서 Criteria를 만들었습니다.이 트릭이 저에게 효과적이었습니다.

Criteria c = session.createCriteria(Child.class,"c");// starting from Child 
    c.add(Restrictions.like("childName", "abc", MatchMode.ANYWHERE)); 
    c.createAlias("parent", "p"); //remember parent is an attribute in Child.class 
    c.add(Restrictions.like("p.parentName", "xyz", MatchMode.ANYWHERE)); 
    c.setProjection(Projections.projectionList().add(Projections.groupProperty("parent"))); //projecting parent which is an attribute of Child.class 

    List<Parent> result = c.list(); //get the result 
    for (Parent p: result) { 
     System.out.println(p); 
    } 

아직 매핑되지 않은 경우 매핑 된 Entity Bean 클래스가 여기에 있습니다.

package com.mazhar.beans; 

import static javax.persistence.GenerationType.IDENTITY; 

import java.util.List; 

import javax.persistence.CascadeType; 
import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.FetchType; 
import javax.persistence.GeneratedValue; 
import javax.persistence.Id; 
import javax.persistence.OneToMany; 
import javax.persistence.Table; 

@Entity 
@Table(name = "parent") 
public class Parent { 
    private Integer idParent; 
    private String parentName; 
    private List<Child> childs; 

    @Id 
    @GeneratedValue(strategy = IDENTITY) 
    @Column(name = "id_parent") 
    public Integer getIdParent() { 
     return idParent; 
    } 
    public void setIdParent(Integer idParent) { 
     this.idParent = idParent; 
    } 

    @Column(name = "parent_name") 
    public String getParentName() { 
     return parentName; 
    } 
    public void setParentName(String parentName) { 
     this.parentName = parentName; 
    } 

    @OneToMany(fetch=FetchType.LAZY, mappedBy="parent", cascade=CascadeType.ALL) 
    public List<Child> getChilds() { 
     return childs; 
    } 
    public void setChilds(List<Child> childs) { 
     this.childs = childs; 
    } 

} 

내 자식 클래스

package com.mazhar.beans; 

import static javax.persistence.GenerationType.IDENTITY; 

import javax.persistence.CascadeType; 
import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.FetchType; 
import javax.persistence.GeneratedValue; 
import javax.persistence.Id; 
import javax.persistence.JoinColumn; 
import javax.persistence.ManyToOne; 
import javax.persistence.Table; 

@Entity 
@Table(name = "child") 
public class Child { 
    private Integer idChild; 
    private String childName; 
    private Parent parent; //this actually we projected in criteria query. 

    @Id 
    @GeneratedValue(strategy = IDENTITY) 
    @Column(name = "id_city", unique = true, nullable = false) 
    public Integer getIdChild() { 
     return idChild; 
    } 

    public void setIdChild(Integer idChild) { 
     this.idChild = idChild; 
    } 

    @Column(name = "city_name", nullable = false) 
    public String getChildName() { 
     return childName; 
    } 

    public void setChildName(String cName) { 
     this.childName = cName; 
    } 

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) 
    @JoinColumn(name = "id_father") 
    public Parent getParent() { 
     return parent; 
    } 

    public void setParent(Parent parent) { 
     this.parent = parent; 
    } 
} 
0

당신이 원하는 방식으로 투사없이 의해 그룹화의 주요 문제는 그것이 작동하지 않습니다 오라클 같은 일부 DBMS에 오라클이를 반환 할 것입니다 오류.

선택을 그룹화하는 경우 선택중인 모든 비 집합 필드를 기준으로 그룹화해야합니다. 예를 들어, MySQL에는 이러한 제한이 없습니다.

내가 사용하고있는 접근 방식은 모든 필터, 순서 및 결과 제한 수가 포함 된 groupProperty 프로젝션 ID 만 선택하는 것입니다. 그런 다음 검색된 ID로 다른 쿼리 필터링을 실행합니다. 그렇게하면, 구현은 DBMS에 의존하지 않게됩니다.

관련 문제