# (Hibernate) in Criteria implizierter Join durch Subquery's



## LadyMilka (11. Nov 2010)

Hallo,
ich arbeite mich derzeit in die Criteria API von Hibernate ein (in Verbindung mit Spring) und stehe nun vor einem Problem.

Ich möchte eine Abfrage über 3 Tabellen machen, und benutze dafür die (gemappte) Relation.
Gestalte ich die Abfrage mit HQL gibt es keine Probleme. Nun möchte ich aber mit Criteria arbeiten und bekomme einen Fehler.
Ich weiß, dass bei Criteria's keine impliziten Joins möglich sind, man dies aber über Subquery's realisierenkann. Das klappt aber mit 3 Tabellen nicht. Hab ich der/die/das Criteria falsch aufgebaut?


```
public class MeldungenDAO extends HibernateDaoSupport{

    public List getWarnungen(String name, Integer typ){
        getHibernateTemplate().setMaxResults(0);
        return getHibernateTemplate().findByNamedParam(
                "select uid.uname, count(mid) "
                + "FROM Meldungen  "
                + "WHERE uid.uname= :name "
                + "AND mid.typ= :typ group by uid",
                new String[]{"name", "typ"}, new Object[]{name, typ});
    }
    
    public List getWarnungenCriteria(String name, Integer typ){
        DetachedCriteria crit = DetachedCriteria.forClass(Meldungen.class)
                .createCriteria("uid")
                    .add(Restrictions.eq("uid.uname", name))
                .createCriteria("mid")
                    .add(Restrictions.eq("mid.typ", typ))
                .setProjection(Projections.groupProperty("uid"))
                .setProjection(Projections.count("mid"));
        List<Meldungen> meld= getHibernateTemplate().findByCriteria(crit);
        return meld;
    }
}
```


```
@Entity
@Table(name="meldungen")
public class Meldungen implements Serializable {

    private Integer id;
    private Date timestamp;
    private User uid;
    private MeldungInfo mid;

    public Meldungen(){        
    }

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Basic(optional=false)
    @OneToOne(targetEntity=db.MeldungInfo.class)
    @JoinColumn(name="mid")
    public MeldungInfo getMid() {
        return mid;
    }

    public void setMid(MeldungInfo mid) {
        this.mid = mid;
    }

    @Basic(optional=false)
    @Temporal(value=TemporalType.TIMESTAMP)
    public Date getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Date timestamp) {
        this.timestamp = timestamp;
    }

    @Basic(optional=false)
    @OneToOne(targetEntity=db.User.class)
    @JoinColumn(name="uid")
    public User getUid() {
        return uid;
    }

    public void setUid(User uid) {
        this.uid = uid;
    }
}
```
Fehler: 
	
	
	
	





```
org.hibernate.QueryException: could not resolve property: mid of: db.User
```
Ist ja richtig, in der Klasse User gibt es keine mid. Scheinbar verschachtelt er die einzelnen Criteria's. Etwa so: 
	
	
	
	





```
DetachedCriteria(Criteria "uid" (Criteria "mid" ))
```
 ich möchte aber 
	
	
	
	





```
DetachedCriteria((Criteria "uid" ) (Criteria "mid" ))
```

Ich hoffe es ist verständlich genug!


----------



## Gast2 (11. Nov 2010)

Du krierst ja auch 2 Criterias...


----------



## SlaterB (11. Nov 2010)

der Fehler scheint erst bei der Projection aufzutreten, verwende

```
DetachedCriteria crit = DetachedCriteria.forClass(Meldungen.class);
crit            .createCriteria("uid")
                    .add(Restrictions.eq("uid.uname", name))
                .createCriteria("mid")
                    .add(Restrictions.eq("mid.typ", typ));

crit            .setProjection(Projections.groupProperty("uid"))
                .setProjection(Projections.count("mid"));
```


----------



## LadyMilka (11. Nov 2010)

SirWayne hat gesagt.:


> Du krierst ja auch 2 Criterias...


Wenn ich das Reference-Manual richtig verstanden habe, macht man das auch so?

Das problem ist, das ich ja das SpringHibernateTemplate verwende. Da geht das ja nicht so einfach mit der Session, wie bei Hibernate. 

Oder bin ich jetzt auf einem falschen Weg?

@SlaterB

gerade Probiert, mit dem gleichen Ergebnis.


----------



## Gast2 (11. Nov 2010)

Ja aber nicht 2 mal an der DetachedCriteria, sondern einmal ist ein session.createCriteria drin.
Ist auch nur ne Vermutung.


----------



## SlaterB (11. Nov 2010)

LadyMilka hat gesagt.:


> @SlaterB
> gerade Probiert, mit dem gleichen Ergebnis.


zeig mal bisschen Code, auch was getHibernateTemplate().findByCriteria(crit); macht, falls das deine eigene Klasse ist,
ich selber benutze Criteria nicht, konnte aber die Fehlermeldung exakt reproduzieren und dann eben lösen

versuche es auch erstmal ohne Projection bzw. projeziere und gruppiere testweise nach anderen Attributen, damit die Fehlemeldung eindeutig wird
(bezieht sich das 'mid of: db.User'-Problem auf die Projection oder die beiden createCriteria-Aufrufe)


----------



## LadyMilka (11. Nov 2010)

getHibernateTemplate().findByCriteria(); sind Methoden von Spring.getHibernateTemplate() Liefert mir das HibernateTemplate, welches in der Servlet.xml definiert ist.

findByCriteria() Fragt mit Hilfe des HibernateTemplates anhand der Criteria Daten ab. Diese Methose nimmt aber nur DetachedCriteria an.


Benutze ich nur:

```
public List getWarnungenCriteria(String name, Integer typ){
        DetachedCriteria crit = DetachedCriteria.forClass(Meldungen.class);
        List<Meldungen> meld= getHibernateTemplate().findByCriteria(crit);
        return meld;
    }
```
wird mir ein richtiges Statement generiert, dass heißt für mich, die Konfiguration und Mapping sind richtig.

```
Hibernate: 
    select
        this_.id as id4_2_,
        this_.mid as mid4_2_,
        this_.timestamp as timestamp4_2_,
        this_.uid as uid4_2_,
        meldunginf2_.id as id2_0_,
        meldunginf2_.`meldung-text` as meldung2_2_0_,
        meldunginf2_.typ as typ2_0_,
        user3_.id as id7_1_,
        user3_.gender as gender7_1_,
        user3_.nachname as nachname7_1_,
        user3_.status as status7_1_,
        user3_.uname as uname7_1_ 
    from
        meldungen this_ 
    left outer join
        `meldungen-info` meldunginf2_ 
            on this_.mid=meldunginf2_.id 
    left outer join
        user user3_ 
            on this_.uid=user3_.id
```

Sobald ich aber nach Zeile 2
	
	
	
	





```
crit.createCriteria("uid").add(Restrictions.eq("uid.uname", name));
```
 einfüge, taucht der erste Fehler auf: 
	
	
	
	





```
org.hibernate.QueryException: could not resolve property: uid of: db.User
```

Edit:
Was ich eben noch probiert hab und auch funktioniert ist:

```
public List getWarnungenCriteria(String name, Integer typ){
        DetachedCriteria crit = DetachedCriteria.forClass(Meldungen.class);
        crit.setProjection(Projections.groupProperty("uid"))
                .setProjection(Projections.count("mid"));
        List<Meldungen> meld= getHibernateTemplate().findByCriteria(crit);
        return meld;
    }
```


----------



## SlaterB (11. Nov 2010)

> could not resolve property: uid of: db.User
klasse, das ist doch inzwischen eine andere Fehlemeldung als zuvor.., immer genau hinschauen,
ich habe selber allerdings auch vergessen, direkt darauf hinzuweisen, denn diesen Fehler hatte ich auch

schreibe
crit.createCriteria("uid").add(Restrictions.eq("uname", name);
statt
crit.createCriteria("uid").add(Restrictions.eq("uid.uname", name);


----------



## LadyMilka (11. Nov 2010)

Klasse, das funkrioniert. Vielen Dank.

die Methode sieht nun so aus und funktioniert auch so wie sie soll.

```
public List getWarnungenCriteria(String name, Integer typ){
        DetachedCriteria crit = DetachedCriteria.forClass(Meldungen.class);
        crit.createCriteria("uid").add(Restrictions.eq("uname", name));
        crit.createCriteria("mid").add(Restrictions.eq("typ", typ));
        crit.setProjection(Projections.groupProperty("uid"))
                .setProjection(Projections.count("mid"));
        List<Meldungen> meld= getHibernateTemplate().findByCriteria(crit);
        return meld;
    }
```
das dazugehörige Statement:

```
Hibernate: 
    select
        this_.uid as y0_ 
    from
        meldungen this_ 
    inner join
        user user1_ 
            on this_.uid=user1_.id 
    where
        user1_.uname=? 
    group by
        this_.uid
```


----------

