Hibernate - could not execute query

Hallo Leute,
ich weiß mein Titel ist nicht äußerst sprechend, aber mir ist gerade nichts eingefallen wie ich mein Problem kurz Beschreiben kann.

Also hier mein Problem.
Ich baue meine Datenbankabfrage durch Criteria auf. Hierfür habe ich mehrere Methoden, die mir mein Criteria immer wieder erweitern und zurück geben.
Das ganze Funktioniert derzeit wunderbar, außer ich beschränke 2 bestimmte Felder zur gleichen Zeit. (Alle anderen Felder kann ich wahllos miteinander beschränken)

Kurz zum Aufbau.
Ich habe eine Filialtabelle.
Eine Filiale hat einen Ort (Land, Bundesland, Kreis) und einen Status.

Der Status ist unterteilt in einen “Hauptstatus” und einen dazugehörigen “Unterstatus”.
Eine Filiale kann mehrere Status haben und ein Stauts kann zu mehreren Filialen gehören.

Daher sieht meine Filial-Hibernateklasse folgendermaßen aus:

	@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
	@JoinColumn(name = "OrtID", insertable=true, updatable=true)		
	private Standort myOrt;

	@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.PERSIST, mappedBy="myFiliale")
	@OrderBy(value = "aktiv asc, erfasstam asc, erfasstum asc")
	private Set <FilialStatus> filialstatus = new HashSet<FilialStatus>();	

Standort sieht nun folgendermaßen aus:

	@Column(name = "PLZ")
	private String plz;
	
	@Column(name = "BEZEICHNUNG",insertable=true, updatable=true)
	private String  ort;

	@ManyToOne(fetch=FetchType.EAGER,cascade = CascadeType.ALL)
	@JoinColumn(name = "KREISID", insertable=true, updatable=true)	
	private Kreis myKreis;
	
	@ManyToOne(fetch=FetchType.EAGER,cascade = CascadeType.ALL)
	@JoinColumn(name="BUNDESLANDID",insertable=true, updatable=true)	
	private Bundesland myBundesland;	
	
	@ManyToOne(fetch=FetchType.EAGER,cascade = CascadeType.ALL)
	@JoinColumn(name = "LANDID", insertable=true, updatable=true)	
	private Land myLand;

und Land folgendermaßen:

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY) 
	@Column(name = "ID")
	private Integer id;
	
	@Column(name = "BEZEICHNUNG", insertable=true, updatable=true)	
	private String bezeichnung;
	
	@Column(name = "LANDKZ", insertable=true, updatable=true)
	private String landkz;
	
	@OneToMany
	private Set <Standort> standort = new HashSet<Standort>();

Filialstatus hat folgenden Aufbau:

	private FilialStatusPK pk = new FilialStatusPK();
	
	@ManyToOne(fetch=FetchType.EAGER,cascade = CascadeType.PERSIST)
	@JoinColumn(name = "UNTERSTATUSID", referencedColumnName="UNTERSTATUSID", insertable=false, updatable=false)			
	private Unterstatus myUnterStatus;
	
	@ManyToOne(fetch=FetchType.EAGER,cascade = CascadeType.PERSIST)
	@JoinColumn(name = "FILIALID", referencedColumnName="FILIALID", insertable=false, updatable=false)
	private Filiale myFiliale;
	
	@Column(name = "ERFASSTAM")
	private Date erfasstam;
	
	@Column(name = "ERFASSTUM")
	private Time erfasstum;
	
	@Column(name = "AKTIV")
	private Integer aktiv;```

und Unterstatus sieht so aus:
```@ManyToOne(fetch=FetchType.EAGER,cascade = CascadeType.PERSIST)
	@JoinColumn(name = "OBERSTATUSID", insertable=true, updatable=true)		
	private Status myStatus;
	
	@Column(name="BEZEICHNUNG")
	private String bezeichnung;```

Nun möchte ich wie erwähnt eine Abfrage machen, bei der ich Land und Status begrenzen möchte.
Hierzu habe ich wie erwähnt die Methoden, die meine Criteria erweitern:

```private Criteria searchKundeByStatus(Criteria crit, Object[] statuse) {
		if (statuse != null && statuse.length > 0) {
			Integer[] statids = new Integer[statuse.length];
			Unterstatus stat = null;
			for (int index = 0; index < statuse.length; index++) {
				stat			= (Unterstatus) statuse[index];
				statids[index] = stat.getUnterstatusID();
			}
			crit.createAlias("filialstatus", "filstat")
			.add(Restrictions.eq("filstat.aktiv", 1))
			.add(Restrictions.in("filstat.myUnterStatus.unterstatusID", statids));			
		}		
		return crit;		
	}	
	
	private Criteria searchKundeByLand(Criteria crit, Object[] laender) {
		if (laender != null && laender.length > 0) {
			Integer[] laenderid = new Integer[laender.length];
			for (int index = 0; index < laender.length; index++) {
				laenderid[index] = ((Land) laender[index]).getID();
			}
			crit.createAlias("myOrt.myLand", "land")
			.add(Restrictions.in("land.id", laenderid));			
		}
		return crit;
	}```

(analog dazu sind auch meine anderen Methoden zur Eingrenzung aufgebaut, die bei diesem Szenario aber keine Rolle spielen)

Habe ich nun mein Criteria zusammengebaut sieht es folgendermaßen aus (toString-Methode):

CriteriaImpl(de.Database.Filiale:this[Subcriteria(myOrt.myLand:land), Subcriteria(filialstatus:filstat)][land.id in (2), filstat.aktiv=1, filstat.myUnterStatus.unterstatusID in (1)])



Führe ich nun ```cirt.list()``` aus, erhalte ich die Exception:
org.hibernate.exception.SQLGrammarException: could not execute query
java.sql.SQLException: [SQL5001] Qualifikationsmerkmal für Spalte oder Tabelle LAND1_ nicht definiert.

schaue ich mir dann das SQL an, was durch Hibernate erzeugt wurde, ist auch an sich klar, warum dieser Fehler auftritt.
[SQL]Hibernate: 
    /* criteria query */ select
        this_.FILIALID as FILIALID5_13_,
        .....
        filstat2_.FILIALID as FILIALID12_0_,
        filstat2_.UNTERSTATUSID as UNTERSTA2_12_0_,
        filstat2_.AKTIV as AKTIV12_0_,
        filstat2_.ERFASSTAM as ERFASSTAM12_0_,
        filstat2_.ERFASSTUM as ERFASSTUM12_0_,
        .....
        standort8_.ID as ID0_4_,
        standort8_.BUNDESLANDID as BUNDESLA4_0_4_,
        standort8_.KREISID as KREISID0_4_,
        standort8_.LANDID as LANDID0_4_,
        standort8_.BEZEICHNUNG as BEZEICHN2_0_4_,
        standort8_.PLZ as PLZ0_4_,
        bundesland9_.ID as ID2_5_,
        bundesland9_.BEZEICHNUNG as BEZEICHN2_2_5_,
        kreis10_.ID as ID1_6_,
        kreis10_.BEZEICHNUNG as BEZEICHN2_1_6_,
        land11_.ID as ID3_7_,
        land11_.BEZEICHNUNG as BEZEICHN2_3_7_,
        land11_.LANDKZ as LANDKZ3_7_,
        .....
        unterstatu16_.UNTERSTATUSID as UNTERSTA1_11_11_,
        unterstatu16_.BEZEICHNUNG as BEZEICHN2_11_11_,
        unterstatu16_.OBERSTATUSID as OBERSTAT3_11_11_,
        status17_.ID as ID10_12_,
        status17_.BEZEICHNUNG as BEZEICHN2_10_12_ 
    from
        FILIALE this_ 
    inner join
        FILIALSTATUS filstat2_ 
            on this_.FILIALID=filstat2_.FILIALID 
    left outer join
        FILIALE filiale5_ 
            on filstat2_.FILIALID=filiale5_.FILIALID 
    left outer join
        STANDORT standort8_ 
            on filiale5_.OrtID=standort8_.ID 
    left outer join
        BUNDESLAND bundesland9_ 
            on standort8_.BUNDESLANDID=bundesland9_.ID 
    left outer join
        KREIS kreis10_ 
            on standort8_.KREISID=kreis10_.ID 
    left outer join
        LAND land11_ 
            on standort8_.LANDID=land11_.ID 
    left outer join
        UNTERSTATUS unterstatu16_ 
            on filstat2_.UNTERSTATUSID=unterstatu16_.UNTERSTATUSID 
    left outer join
        STATUS status17_ 
            on unterstatu16_.OBERSTATUSID=status17_.ID 
    where
        land1_.ID in (
            ?
        ) 
        and filstat2_.AKTIV=? 
        and filstat2_.UNTERSTATUSID in (
            ?
        )
[/SQL]

Es wird ein ALIAS für "LAND" namens "land11_" erstellt. 
In der WHERE-Klausel wird aber mit "land1_" gearbeitet.

Hat hier jemand eine Ahnung, warum das der Fall ist?
Ich hoffe ich habe genug Code gepostet. Hab den Code etwas abgekürzt um den Post nicht komplett zu überladen.
Wie erwähnt, tritt der Fehler wirklich nur dann auf, wenn ich Filialstatus und Land zusammen beschränken will.
Nur Filialstatus mit irgendetwas anderem bzw. nur Land mit irgendetwas anderem funktioniert einwandfrei.

Danke schon mal

Funktioniert es, wenn Du die Abfrage mit JPQL formulierst statt mit Criteria API?
Das würde das Problem eingrenzen.

Ja tut es.
(Ich arbeite mit Hibernate und habe deshalb eine HQL gemacht, kommt ja aber in dem Bezug nicht drauf an)
Also folgendes kurzes HQL funktioniert:

	public void test() {
		try {
			String hql 		= "FROM Filiale as f "+
					"INNER JOIN f.filialstatus as filstat "+
					"LEFT OUTER JOIN f.myOrt as sort "+
					"LEFT OUTER JOIN sort.myLand as la "+
					"where la.id in (2) " +
					"AND filstat.aktiv = 1 "+
					"AND filstat.myUnterStatus.unterstatusID in (1)";
			Session session 	= HibernateUtil.getSession();
			Query query 		= session.createQuery(hql);
			List rs				= query.list();
			for (Object object : rs) {
				System.out.println(object);
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}

Hibernate Ausgabe auf der Konsole:

Hibernate: 
    /* 
FROM
    Filiale as f 
INNER JOIN
    f.filialstatus as filstat 
LEFT OUTER JOIN
    f.myOrt as sort 
LEFT OUTER JOIN
    sort.myLand as la 
where
    la.id in (
        2
    ) 
    AND filstat.aktiv = 1 
    AND filstat.myUnterStatus.unterstatusID in (
        1
    ) */ select
        filiale0_.FILIALID as FILIALID5_0_,
        filialstat1_.FILIALID as FILIALID12_1_,
        filialstat1_.UNTERSTATUSID as UNTERSTA2_12_1_,
        standort2_.ID as ID0_2_,
        land3_.ID as ID3_3_,
        filiale0_.Aktualisiert_Am as Aktualis2_5_0_,
        filiale0_.Dokumentenpfad as Dokument3_5_0_,
        filiale0_.EMail as EMail5_0_,
        filiale0_.erfasst_am as erfasst5_5_0_,
        filiale0_.Fax as Fax5_0_,
        filiale0_.FILIALNR as FILIALNR5_0_,
        filiale0_.flaeche as flaeche5_0_,
        filiale0_.Homepage as Homepage5_0_,
        filiale0_.INTERESSEKZ as INTERES10_5_0_,
        filiale0_.Mitarbeiterzahl as Mitarbe11_5_0_,
        filiale0_.ADRESSHERKUNFTID as ADRESSH21_5_0_,
        filiale0_.KategorieID as Kategor22_5_0_,
        filiale0_.OrtID as OrtID5_0_,
        filiale0_.UnternehmenID as Unterne24_5_0_,
        filiale0_.VERTRIEBSSCHIENEID as VERTRIE25_5_0_,
        filiale0_.Name as Name5_0_,
        filiale0_.Notiz as Notiz5_0_,
        filiale0_.Strasse as Strasse5_0_,
        filiale0_.telefon as telefon5_0_,
        filiale0_.umsatz as umsatz5_0_,
        filiale0_.VERKAUFSCHANCE as VERKAUF17_5_0_,
        filiale0_.WERBUNGKZ as WERBUNGKZ5_0_,
        filiale0_.wiedervorlage as wiederv19_5_0_,
        filiale0_.ZentralKZ as ZentralKZ5_0_,
        filialstat1_.AKTIV as AKTIV12_1_,
        filialstat1_.ERFASSTAM as ERFASSTAM12_1_,
        filialstat1_.ERFASSTUM as ERFASSTUM12_1_,
        standort2_.BUNDESLANDID as BUNDESLA4_0_2_,
        standort2_.KREISID as KREISID0_2_,
        standort2_.LANDID as LANDID0_2_,
        standort2_.BEZEICHNUNG as BEZEICHN2_0_2_,
        standort2_.PLZ as PLZ0_2_,
        land3_.BEZEICHNUNG as BEZEICHN2_3_3_,
        land3_.LANDKZ as LANDKZ3_3_ 
    from
        FILIALE filiale0_ 
    inner join
        FILIALSTATUS filialstat1_ 
            on filiale0_.FILIALID=filialstat1_.FILIALID 
    left outer join
        STANDORT standort2_ 
            on filiale0_.OrtID=standort2_.ID 
    left outer join
        LAND land3_ 
            on standort2_.LANDID=land3_.ID 
    where
        (
            land3_.ID in (
                2
            )
        ) 
        and filialstat1_.AKTIV=1 
        and (
            filialstat1_.UNTERSTATUSID in (
                1
            )
        )

hibernate criteria "Qualifikationsmerkmal" findet nicht viel mehr als deine beiden Threads im Internet,
mit englischer Fehlermeldung wäre es vielleicht aussichtsreicher, an ähnliche Fälle zu kommen, so es sie je bereits gegeben hat

keine Ahnung wie einzustellen, aber wenn es dir wichtig ist, dann vielleicht ein Ansatzpunkt


in jedem Fall ist es ein interner Bug, ein Zustand der auch durch falsche Bedienung nicht vorkommen dürfte,
ein weiteres ‘Betätigungsfeld’ wäre noch, den Fehler weiter einzugrenzen, die Komplexität der Query abzubauen auf ein überschaubares kleines Beispiel

evtl. ergeben sich mit Umstellung im Mapping, allein schon Rehenfolge, sogar Konstellationen für eine erfolgreiche Query,
aber sinnvolle Lösung fürs Programm ist das nicht,
vielleicht für Hibernate-Bug-Meldung aufgeräumter

Ich muss mal schauen, wie ich das umstellen kann.

Die Fehlermeldung an sich verstehe ich ja aber. Er findet eben “Land_1” nicht, da nur “Land_11” als Alias definiert wurde.
Dennoch versuche ich es mal in Englisch ausgeben zu lassen. Mit ein wenig Glück finde ich dann etwas beim googlen.

So ich habe mir mal ein kleineres Beispiel geschaffen. Bei dem nur noch die Tabellen die bei dieser Konstallation abgefragt werden auch wirklich im Query vorhanden sind:

Hibernate: 
    /* criteria query */ select
        this_.FILIALID as FILIALID5_6_,
        this_.FILIALNR as FILIALNR5_6_,
        this_.OrtID as OrtID5_6_,
        this_.Name as Name5_6_,
        this_.Strasse as Strasse5_6_,
        this_.ZentralKZ as ZentralKZ5_6_,
        filstat2_.FILIALID as FILIALID12_0_,
        filstat2_.UNTERSTATUSID as UNTERSTA2_12_0_,
        filstat2_.AKTIV as AKTIV12_0_,
        filstat2_.ERFASSTAM as ERFASSTAM12_0_,
        filstat2_.ERFASSTUM as ERFASSTUM12_0_,
        filiale5_.FILIALID as FILIALID5_1_,
        filiale5_.FILIALNR as FILIALNR5_1_,
        filiale5_.OrtID as OrtID5_1_,
        filiale5_.Name as Name5_1_,
        filiale5_.Strasse as Strasse5_1_,
        filiale5_.ZentralKZ as ZentralKZ5_1_,
        standort6_.ID as ID0_2_,
        standort6_.LANDID as LANDID0_2_,
        standort6_.BEZEICHNUNG as BEZEICHN2_0_2_,
        standort6_.PLZ as PLZ0_2_,
        land7_.ID as ID3_3_,
        land7_.BEZEICHNUNG as BEZEICHN2_3_3_,
        land7_.LANDKZ as LANDKZ3_3_,
        unterstatu8_.UNTERSTATUSID as UNTERSTA1_11_4_,
        unterstatu8_.BEZEICHNUNG as BEZEICHN2_11_4_,
        unterstatu8_.OBERSTATUSID as OBERSTAT3_11_4_,
        status9_.ID as ID10_5_,
        status9_.BEZEICHNUNG as BEZEICHN2_10_5_ 
    from
        FILIALE this_ 
    inner join
        FILIALSTATUS filstat2_ 
            on this_.FILIALID=filstat2_.FILIALID 
    left outer join
        FILIALE filiale5_ 
            on filstat2_.FILIALID=filiale5_.FILIALID 
    left outer join
        STANDORT standort6_ 
            on filiale5_.OrtID=standort6_.ID 
    left outer join
        LAND land7_ 
            on standort6_.LANDID=land7_.ID 
    left outer join
        UNTERSTATUS unterstatu8_ 
            on filstat2_.UNTERSTATUSID=unterstatu8_.UNTERSTATUSID 
    left outer join
        STATUS status9_ 
            on unterstatu8_.OBERSTATUSID=status9_.ID 
    where
        land1_.ID in (
            ?, ?, ?
        ) 
        and filstat2_.AKTIV=? 
        and filstat2_.UNTERSTATUSID in (
            ?, ?
        )

Was mir jetzt hierbei noch auffällt:
ich habe Filiale 2x in dem Query drin.
Einmal als Haupttabelle (Alias: “this_”)
und dann noch hier:

//...
    inner join
        FILIALSTATUS filstat2_ 
            on this_.FILIALID=filstat2_.FILIALID 
    left outer join
        FILIALE filiale5_ 
            on filstat2_.FILIALID=filiale5_.FILIALID 
//...
  1. Warum ist das der Fall?
  2. Könnte das den anderen Fehler auslösen?

habe die Hibernateversion von 3.6.8 mal noch auf 3.6.10 geupdatet. Hat aber auch nichts gebracht.
Ein update auf eine 4er Version dauert deutlich länger und da muss ich mich erst in die Änderungen einarbeiten, deshalb habe ich das noch nicht versucht.

EDIT: Ich habe auch versucht die Mappings mal ein wenig umzustellen.
Aber bisher hat noch nichts den Fehler beheben können.

Der join repräsentiert das @ManyToOne-Mapping von FilialStatus auf Filiale.

Falls die Beziehung FilialStatus->Filiale nicht navigierbar sein muss, kannst Du dieses Mapping ja mal weglassen.
Falls doch, hilft evtl. den FetchType auf LAZY zu stellen.

Edit:

Das kling sowieso eher nach einer @ManyToMany-Beziehung.

Ist es ja auch.
Da ich die Filialstatus-Tabelle aber noch um Felder erweitert habe, habe ich dafür eine eigene Klasse geschrieben (s.o.)
Zu dieser Klasse besteht nur eine ManyToOne-Beziehung.

Also die ManyToMany-Beziehung ist zwischen “Filiale” und “Unterstatus” durch die Tabelle “FilialStatus” realisiert.

Ich habe es nun gerade mal probiert und in FilialStatus die Beziehung zu Filiale auf FetchType LAZY gestellt.
Und siehe da, es geht.

Jetzt muss ich nur schauen ob mir das an anderer Stelle ein Problem macht.
Und zweitens würde ich gerne verstehen, warum der Fehler dann nicht mehr auftritt. Jemand eine Erklärung?

Weil der join, der vorher die Probleme machte, bei LAZY nicht mehr automatisch generiert wird.

Abgesehen davon sollte es natürlich auch mit EAGER funktionieren, möglicherweise ein Bug in der Criteria API, wie SlaterB schon angemerkt hat.

Okay. Ich dachte das es evtl dann doch kein Bug ist sondern ein modellierungsfehler meinerseits.
Immerhin funktioniert es nun.
Bei Gelegenheit upgrade ich mal auf die neuste Hibernateversion. Wenn der Fehler dann noch auftritt werde ich es mal als Bug melden.