I write named query like this
<query name="GET_QUESTIONS_BY_TEST_ID">select tq from TestQuestion as tq inner join tq.question as
q
where
tq.testQuestionIdentifer.versionId=(select
max(tq.testQuestionIdentifer.versionId) from TestQuestion tq_inner
where
tq_inner.testQuestionIdentifer.testId=:testId) and
tq.testQuestionIdentifer.testId=:testId
</query>
And when I get result I have a problem. When I write just from TestQuestion I get List<Object[Object[]]> with Question and TestQuestion objects. When I write select tq I get LazyInitializationException. I want to get List but can't.
UPDATED
I decided add other part my hbm
<class name="by.bsuir.testapp.model.TestQuestion" table="TEST_QUESTION"
lazy="true">
<composite-id name="testQuestionIdentifer"
class="by.bsuir.testapp.model.TestQuestionIdentifer">
<key-property name="testId" column="TEST_ID" />
<key-property name="versionId" column="VERSION_ID" />
<key-property name="questionId" column="QUESTION_ID" />
</composite-id>
<many-to-one name="question" class="by.bsuir.testapp.model.Question"
fetch="join" insert="false" update="false">
<column name="QUESTION_ID" />
</many-to-one>
</class>
I find that exist 11.4.1.2. Queries that return tuples in documentation of Hibernate documentation
How I should write named query for rignt result?
I don't get your problem.
Your query (select tq from TestQuestion as tq... and from TestQuestion) should both return List<TestQuestion> instead of List<Object[][]>
LazyInitializationException normally occur when there is lazy-fetching occurring, but the related session of the entity is closed already (please correct me if I am wrong, just from my bare memory I thought it is LazyInitializationException). It has nothing to do with named query. Please make sure your transaction control etc is setup correctly.
Related
Consider the following hibernate mapping (using hibernate 4):
Answer with a DataCollection joined-subclass:
<hibernate-mapping>
<class name="Answer" table="answer">
<many-to-one name="answeredForm" class="AnsweredForm" fetch="select">
<column name="answered_form_id" />
</many-to-one>
<joined-subclass table="data_collection" name="DataCollection" extends="Answer">
<key column="id"></key>
</joined-subclass>
</class>
</hibernate-mapping>
AnsweredForm with a PatientForm joined-subclass:
<hibernate-mapping>
<class name="AnsweredForm" table="answered_form">
<joined-subclass table="patientForm" name="PatientForm" extends="AnsweredForm">
<many-to-one name="patient" class="Patient" fetch="join">
<column name="patient_id" />
</many-to-one>
</joined-subclass>
</class>
</hibernate-mapping>
Question: Using HQL, how can you ask for "all datcollections whose AnsweredForm belongs to patient x"?
SELECT answer FROM DataCollection answer
JOIN answeredForm answeredForm
WHERE answer.answeredForm.patient.code=:patientCode
This HQL yields the error:
ERROR: missing FROM-clause entry for table "answeredfo2_2_"
And rightly so, as the SQL translation of this query is:
SELECT datacollec0_.id AS id1_62_,
datacollec0_1_.free_text AS free_tex2_62_
FROM data_collection datacollec0_
INNER JOIN answer datacollec0_1_
ON datacollec0_.id = datacollec0_1_.id
CROSS JOIN answered_form answeredfo1_
CROSS JOIN answered_form answeredfo2_
CROSS JOIN patient patient3_
WHERE datacollec0_1_.answered_form_id = answeredfo1_.id
AND datacollec0_1_.answered_form_id = answeredfo2_.id
AND answeredfo2_2_.patient_id = patient3_.id
AND CASE
WHEN answeredfo1_4_.id IS NOT NULL THEN 4
WHEN answeredfo1_1_.id IS NOT NULL THEN 1
WHEN answeredfo1_2_.id IS NOT NULL THEN 2
WHEN answeredfo1_3_.id IS NOT NULL THEN 3
WHEN answeredfo1_.id IS NOT NULL THEN 0
END = 2
AND patient3_.code = ?
Try to use the following hql:
SELECT a FROM Answer a
JOIN a.answeredForm af
WHERE af.patient.code=:patientCode
Look at this part of the hibernate documentation for additional explanations and examples.
I'm mapping some entities using Hibernate 3 for my project and simply explained I've got kind of this:
Student entity (tstudent table)
UniversityStudent entity (tuniversitystudent table)
University entity (tuniversity table)
UniversityStudent extends from Student and has its own attributes, like the university itself, which is a foreign key into the tuniversitystudent table. It is also mapped like a subclass into the Student class, using a discriminator field:
<class name="mycompany.Student" table="tstudent" discriminator-value="BASIC">
<id name="id" column="id" type="integer">
<generator class="native" />
</id>
<discriminator column="type" />
<property name="name" column="name" />
<property name="surname" column="surname" />
<property name="phoneNumber" column="phone_number" />
<subclass discriminator-value="UNIVERSITY"
name="mycompany.UniversityStudent">
<join table="tuniversitystudent">
<key column="id_student" />
<many-to-one name="university" class="mycompany.University">
<column name="id_university" />
</many-to-one>
</join>
</subclass>
</class>
Well, now I want to have a Set collection with the UniversityStudent entities for each University. So I map it like that:
<class name="mycompany.University" table="tuniversity">
<id name="id" column="id" type="integer">
<generator class="native" />
</id>
<property name="name" column="name" />
<set name="universityStudents" table="tuniversitystudent">
<key>
<column name="id_university" />
</key>
<one-to-many class="mycompany.UniversityStudent" />
</set>
</class>
My problem comes when I want to load a University object, Hibernate complains that id_university doesn't exist in tstudent table. I checked the generated SQL query and it really tries to load it from tstudent.
Unknown column 'student0_.id_university' in 'field list'
It seems that it's recognizing that it is a subclass of the basic Student and tries to join the collection using a field in the parent table, but however the field is actually in the child table, because only university students can have a University assigned.
I tried another workaround which seems to work but it's not valid for me, that's mapping the UniversityStudent as a joined-subclass instead of a subclass with a join inside:
<joined-subclass name="mycompany.UniversityStudent" table="tuniversitystudent">
<key column="id_student" />
<many-to-one name="university" class="mycompany.University">
<column name="id_university" />
</many-to-one>
</joined-subclass>
However, I'm interested in keeping it as a subclass with a discriminator value. Any idea?
I checked out some resources and finally got into this bug: https://hibernate.atlassian.net/browse/HHH-1015, which looks absolutely compatible with your case. Checkout this old question as well, again very similar to your case.
I firstly read the definition of table per sublass given by Hibernate (I know, it is for version 3.3 but I couldn't find the same source for Hibernate 4): joined-subclass seems (to me) to be a custom implementation of subclass using a discriminator provided by Hibernate and that is a good reason to stay away from its usage. However, from what I know, the mappings table per sublass and table per subclass using a discriminator should be equivalent, that's why I believe the bug I pointed you out is really still open.
If you have time and will, you can try to use another JPA provider and check if you still run in the same issue. JPA 2.0 specifications is a thing, provider implementation is another! I recently run into another bug (related to #IdClass) which forced me to try EclipseLink and the configuration which was not working with Hibernate was right with Eclipse Link
Seems you can use Custom SQL (or HQL) for loading. Haven't tried it myself, but looks like, hmm, at least as a last resort, it provides a decent solution.
Define the query in your HBM:
<sql-query name="universityStudents">
<load-collection alias="unistu" role="University.universityStudents"/>
SELECT unistu.*, student.*
FROM tuniversitystudent unistu
JOIN tstudent student
ON unistu.id_student = student.id
WHERE unistu.id_university = :id
</sql-query>
And then use it inside University:
<set name="universityStudents" inverse="true">
<key/>
<one-to-many class="mycompany.UniversityStudent"/>
<loader query-ref="universityStudents"/>
</set>
I'm trying to figure out how to map the relationship between two tables through a join table that has some meta data in it. In short, the three tables represent the page of a form, and each page can contain any number of elements (questions.) For some reason, the original developer decided that elements could be used on multiple forms. This means that the weight column, used to order the elements on the page, is in the join table.
How the heck do I map this in XML? (Annotations aren't an option.)
For the join table, I guess it's like this:
<class name="com.foo.bar.model.db.ApplicationPageElements"
table="APPLICATION_PAGE_ELEMENTS">
<composite-id name="id" class="com.foo.bar.model.db.ApplicationPageElementsKey">
<key-property name="pageId" column="page_id"/>
<key-property name="elementId" column="element_id"/>
</composite-id>
<property name="weight" type="java.lang.Long">
<column name="WEIGHT" precision="0" />
</property>
</class>
My instincts have me wanting to do something like this from the ApplicationPage side of things:
<set name="applicationElements" table="applicationPageElement">
<key column="page_id"/>
<many-to-many column="element_id" unique="true"
class="com.foo.bar.model.db.ApplicationElements" />
</set>
And that's where I get all slack-jawed, stare at the screen, and sob.
We're using .hbm.xml files to map our database. We also made the decision to not change our database.
Any ideas on how to map this in XML?
Instead of thinking of the relationship between application_page and application_element as many to many, think of it as a one to many relationship from application_page to ApplicationPageElements and a one to many relationship from application_element to ApplicationPageElements.
In your application_page xml mapping add this:
<set name="applicationElements" inverse="true">
<key column="page_id"/>
<one-to-many class="ApplicationPageElements"/>
</set>
page_id forms a part of the primary key of the join table. So, mark the collection as inverse.
Your mapping for the join table is correct. But, with the above change current mapping of your join table you can navigate from application_page to ApplicationPageElements. To navigate from application_page to application_element (via ApplicationPageElements) add a many to one relationship in join table mapping.
<class name="com.foo.bar.model.db.ApplicationPageElements"
table="APPLICATION_PAGE_ELEMENTS">
<composite-id name="id" class="com.foo.bar.model.db.ApplicationPageElementsKey">
<key-property name="pageId" column="page_id"/>
<key-property name="elementId" column="element_id"/>
</composite-id>
<property name="weight" type="java.lang.Long">
<column name="WEIGHT" precision="0" />
</property>
<many-to-one name="elements" class="ApplicationElements"
column="element_id" not-null="true" insert="false" update="false"/>
<many-to-one name="page" class="ApplicationPage"
column="page_id" not-null="true" insert="false" update="false"/>
</class>
Note that in the above many-to-one mapping, insert and update attributes are set to false. This is necessary because the columns are mapped twice, once in the composite key (which is responsible for insertion of the values) and again for the many-to-one associations.
The above use case is mentioned in detail in the book: Java Persistence with Hibernate.
There is a Java SE project with Hibernate ORM. I feel that the problem is trivial, but need some help.
There is a code snippet:
SessionFactory factory = new Configuration().configure().buildSessionFactory();
Session s = factory.openSession();
int id = 1;
ExperimentSetResult experimentSetResult = (ExperimentSetResult)s.get(ExperimentSetResult.class, id);
System.out.println("size: " + experimentSetResult.getExperimentResults().size());
System.out.println("id[0]: " + experimentSetResult.getExperimentResults().get(0).getId());
I get a NullPointerException for the last string of code (when accessing the 0-th element of a collection associated with an object loaded recently).
There are the hbm files snippets:
ExperimentResult.hbm.xml:
<hibernate-mapping>
<class name="rmocommon.driverreaction.ExperimentResult" table="experiment_results">
<id name="id" type="int">
<generator class="increment"/>
</id>
<many-to-one class="rmocommon.driverreaction.ExperimentSetResult" name="ExperimentSetResult" column="ExperimentSetResultId" not-null="true" />
</class>
</hibernate-mapping>
ExperimentSetResult.hbm.xml:
<hibernate-mapping>
<class name="rmocommon.driverreaction.ExperimentSetResult" table="experiment_set_results">
<id name="id" type="int">
<generator class="increment"/>
</id>
<list name="ExperimentResults" cascade="all-delete-orphan" inverse="true">
<key column="ExperimentSetResultId" not-null="true"/>
<list-index column="Id"/>
<one-to-many class="rmocommon.driverreaction.ExperimentResult"/>
</list>
</class>
</hibernate-mapping>
What's wrong with mapping or with my source code?
UPDATE:
Here is an output and a stack trace:
Hibernate: select experiment0_.id as id4_2_, experiment0_.StartedDate as StartedD2_4_2_, experiment0_.FinishedDate as Finished3_4_2_, experiment0_.DeviceOutput as DeviceOu4_4_2_, person1_.id as id0_0_, person1_.Login as Login0_0_, person1_.LastName as LastName0_0_, person1_.Patronymic as Patronymic0_0_, person1_.FirstName as FirstName0_0_, person1_.Age as Age0_0_, experiment2_.id as id1_1_, experiment2_.TestMode as TestMode1_1_, experiment2_.TransportType as Transpor3_1_1_, experiment2_.TransportStartSpeed as Transpor4_1_1_, experiment2_.RoadType as RoadType1_1_, experiment2_.RoadLength as RoadLength1_1_, experiment2_.DirectionLeft as Directio7_1_1_, experiment2_.RespondToFirstEffort as RespondT8_1_1_, experiment2_.SoundOnFirstEffort as SoundOnF9_1_1_, experiment2_.ScaleObjects as ScaleOb10_1_1_, experiment2_.ShowTransportSpeed as ShowTra11_1_1_, experiment2_.BarrierXMin as Barrier12_1_1_, experiment2_.BarrierXMax as Barrier13_1_1_, experiment2_.ReactionTime as Reactio14_1_1_, experiment2_.SoundOnBarrierAppearance as SoundOn15_1_1_, experiment2_.AllowedCheatCount as Allowed16_1_1_ from experiment_set_results experiment0_ left outer join persons person1_ on experiment0_.id=person1_.id left outer join experiment_set_settings experiment2_ on experiment0_.id=experiment2_.id where experiment0_.id=?
Hibernate: select experiment0_.ExperimentSetResultId as Experim11_4_1_, experiment0_.id as id1_, experiment0_.Id as Id1_, experiment0_.id as id2_0_, experiment0_.Distance as Distance2_0_, experiment0_.Crash as Crash2_0_, experiment0_.BrakingStarted as BrakingS4_2_0_, experiment0_.BrakingStartedTime as BrakingS5_2_0_, experiment0_.BrakingStartedDistance as BrakingS6_2_0_, experiment0_.BarrierX as BarrierX2_0_, experiment0_.Number as Number2_0_, experiment0_.Time as Time2_0_, experiment0_.Valid as Valid2_0_, experiment0_.ExperimentSetResultId as Experim11_2_0_ from experiment_results experiment0_ where experiment0_.ExperimentSetResultId=?
size: 6
Exception in thread "main" java.lang.NullPointerException
at hibernateTest.HibernateTest.main(HibernateTest.java:45)
Java Result: 1
Might be that your mapping is wrong. Your list-index column definetly should not be ID.
If you really need the ordering, you better create a separate column for that, otherwise you will encounter problems.
Another thing I've noticed. You don't have to specify the inverse on the one-to-many relationship.
It's been a while I've seen hbm.xml files, can you use annotations? They are much easier to understand.
Ok so I'm having bit of a problem with my Hibernate mappings and getting the desired behavior.
Basically what I have is the following Hibernate mapping:
<hibernate-mapping>
<class name="com.package.Person" table="PERSON" schema="MYSCHEMA" lazy="false">
<id name="personId" column="PERSON_ID" type="java.lang.Long">
<generator class="sequence">
<param name="sequence">PERSON_ID_SEQ</param>
</generator>
</id>
<property name="firstName" type="string" column="FIRST_NAME">
<property name="lastName" type="string" column="LAST_NAME">
<property name="age" type="int" column="AGE">
<set name="skills" table="PERSON_SKILL" cascade="all-delete-orphan">
<key>
<column name="PERSON_ID" precision="12" scale="0" not-null="true"/>
</key>
<many-to-many column="SKILL_ID" unique="true" class="com.package.Skill"/>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.package.Skill" table="SKILL" schema="MYSCHEMA">
<id name="skillId" column="SKILL_ID" type="java.lang.Long">
<generator class="sequence">
<param name="sequence">SKILL_ID_SEQ</param>
</generator>
</id>
<property name="description" type="string" column="DESCRIPTION">
</class>
</hibernate-mapping>
So lets assume that I have already populated the Skill table with some skills in it. Now when I create a new Person I want to associate them with a set of skills that already exist in the skill table by just setting the ID of the skill. For example:
Person p = new Person();
p.setFirstName("John");
p.setLastName("Doe");
p.setAge(55);
//Skill with id=2 is already in the skill table
Skill s = new Skill()
s.setSkillId(2L);
p.setSkills(new HashSet<Skill>(Arrays.asList(s)));
PersonDao.saveOrUpdate(p);
If I try to do that however I get an error saying:
WARN (org.slf4j.impl.JCLLoggerAdapter:357) - SQL Error: 1407, SQLState: 72000
ERROR (org.slf4j.impl.JCLLoggerAdapter:454) - ORA-01407: cannot update ("MYSCHEMA"."SKILL"."DESCRIPTION") to NULL
ERROR (org.slf4j.impl.JCLLoggerAdapter:532) - Could not synchronize database state with session
org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
The reason I am getting this error I think is because Hibernate sees that the Skill with Id 2 has 'updated' its description to null (since I never set it) and tries to update it. But I don't want Hibernate to update this. What I want it to do is insert the new Person p and insert a record into the join table, PERSON_SKILL, that matches p with the skill in the SKILL table with id=2 without touching the SKILL table.
Is there anyway to achieve this behavior?
Instead of creating the Skill object yourself:
//Skill with id=2 is already in the skill table
Skill s = new Skill()
s.setSkillId(2L);
p.setSkills(new HashSet<Skill>(Arrays.asList(s)));
You should be retrieving it from the Hibernate Session:
Skill s = (Skill) session.get(Skill.class, 2L);
p.setSkills(new HashSet<Skill>(Arrays.asList(s)));
This way the Session thinks that the skill contained in p.skills is persistent, and not transient.
This may be possible if you don't cascade all-delete-orphan which is explicitely telling hibernate to cascade the changes.
But the right way would be IMO to load load the desired Skill entity from the database and to add it to the set of skills of the Person.