I am currently trying to create two simple one-to-one mappings using Hibernate but somehow it doesn't work as I want it to.
My primary class is called MailAccount and its mapping looks like this:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated 26.04.2011 14:49:15 by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping package="test.account">
<class name="MailAccount" table="MAILACCOUNTS" dynamic-update="true">
<id name="id" column="MAIL_ACCOUNT_ID">
<generator class="native" />
</id>
<one-to-one name="incomingServer" cascade="all" />
<one-to-one name="outgoingServer" cascade="all" />
</class>
</hibernate-mapping>
The server mapping file looks like this:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 02.05.2011 12:32:52 by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="test.server.MailServer" table="MAILSERVER">
<id name="id" type="long" access="field">
<column name="MAIL_SERVER_ID" />
<generator class="native" />
</id>
<one-to-one name="mailAccount" class="test.account.MailAccount" foreign-key="MAIL_SERVER_ID"></one-to-one>
</class>
</hibernate-mapping>
Now, if I let Hibernate create the tables, I get pretty much that what I want: A table "MailAccount" with the column "MAIL_ACCOUNT_ID" and another table "MailServer" also with a column for the id.
If I call session.save(mailAccountInstance);, Hibernate correctly saves the data to the tables.
BUT once I try to load the data into a MailAccount instance, Hibernate only loads the "incomingServer" property into a new MailAccount instance and the outgoingServer property is empty.
I also don't understand how Hibernate joins both tables together since the table "MailServer" doesn't save the id of the MailAccount each server belongs to as a foreign key.
How can I fix this?
Thanks in advance!
Ps: I am pretty new to Hibernate, so don't beat me up to much for obvious mistakes :-)
I suggest taking a look at the Association Mappings chapter in the Hibernate reference manual. For a bidirectional one-to-one mapping, it's suggested to use a <one-to-one> on one end and <many-to-one unique="true"> on the other end.
Related
I have two tables in a MySQL database: COURSE and COURSE_SESSION.
COURSE has two fields : code(primary key) and title.
CourseSession has a field called course_code which is a foreign key linked to an element of Course.
I want to do somthing like this but using the Criteria API in Java :
SELECT * FROM COURSE_SESSION join COURSE
WHERE course_code = code AND title like "%substring%";
Both tables are mapped correctly with hibernate.
I tried this :
Criteria criter = s.createCriteria(CourseSession.class);
criter.add(Restrictions.like("courseCode.title", "%substring%"));
But I end up with an error :
HTTP 500 - could not resolve property: courseCode.title of: org.xxx.core.entity.CourseSession
message could not resolve property: courseCode.title of: org.xxx.core.entity.CourseSession
exception
org.hibernate.QueryException: could not resolve property: courseCode.title of: fr.utbm.lo54.core.entity.CourseSession
org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:81)
org.hibernate.persister.entity.AbstractPropertyMapping.toColumns(AbstractPropertyMapping.java:96)
org.hibernate.persister.entity.BasicEntityPropertyMapping.toColumns(BasicEntityPropertyMapping.java:62)
org.hibernate.persister.entity.AbstractEntityPersister.toColumns(AbstractEntityPersister.java:1443)
org.hibernate.loader.criteria.CriteriaQueryTranslator.getColumns(CriteriaQueryTranslator.java:483)
org.hibernate.loader.criteria.CriteriaQueryTranslator.getColumnsUsingProjection(CriteriaQueryTranslator.java:443)
org.hibernate.criterion.SimpleExpression.toSqlString(SimpleExpression.java:68)
org.hibernate.loader.criteria.CriteriaQueryTranslator.getWhereCondition(CriteriaQueryTranslator.java:380)
org.hibernate.loader.criteria.CriteriaJoinWalker.(CriteriaJoinWalker.java:114)
org.hibernate.loader.criteria.CriteriaJoinWalker.(CriteriaJoinWalker.java:83)
org.hibernate.loader.criteria.CriteriaLoader.(CriteriaLoader.java:92)
org.hibernate.impl.SessionImpl.list(SessionImpl.java:1687)
org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347)
fr.utbm.lo54.core.servlet.SearchData.doGet(SearchData.java:52)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
The strange thing is that if I do a Restriction on courseCode.code with Restrictions.like("courseCode.code", "%substring%"), it works fine.
EDIT
Course.hbm.xml :
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.xxx.core.entity">
<class name="Course" table="COURSE">
<id name="code" column="CODE">
<generator class ="identity"/>
</id>
<property name="title" column="TITLE" not-null="true"/>
</class>
</hibernate-mapping>
CourseSession.hbm.xml :
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.xxx.core.entity">
<class name="CourseSession" table="COURSE_SESSION">
<id name="id" column="ID">
<generator class="identity" />
</id>
<property name="startDate" column="START_DATE" not-null="true" />
<property name="endDate" column="END_DATE" not-null="true" />
<many-to-one name="courseCode" column="COURSE_CODE" />
<many-to-one name="locationId" column="LOCATION_ID" />
</class>
</hibernate-mapping>
create an alias for the field first to achieve this.
try the below code, it should help
criter.createAlias("courseCode","courseCode");//course code is the association variable in your pojo class.
I have the following pretty simple many-to-one relationship between Person and their parents/children (which also are instances of Person again).
Person.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 04.05.2011 15:02:31 by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="test.Person" table="PERSONS">
<id name="id" type="long" access="field">
<column name="PERSON_ID" />
<generator class="native" />
</id>
<bag name="children" table="PERSONS" lazy="false" inverse="true" cascade="all">
<key column="PERSON_ID" not-null="false"></key>
<one-to-many class="test.Person" />
</bag>
<many-to-one name="parent" column="PARENT_ID" not-null="false" />
</class>
</hibernate-mapping>
Now, the problem in my case is that I have instances of Person which do not have parents (e.g. orphans).
If I try to persist these objects, I get:
java.sql.SQLException: null, message
from server: "Column
'PARENT_ID' cannot be null"
If I set not-null="true" in the mapping file, I get:
org.hibernate.PropertyValueException:
not-null property references a null or
transient value: test.parent
What's the magic trick here?
Valmar, since you are getting a SQL Exception, probably your COLUMN 'PARENT_ID' have a not null constraint. Check your table DDL. What database are you using?
I am using Hibernate. My database is as follows
A Category has many attributes
class category
contains
private Set <Attribute> AllAttributes= new HashSet <Attribute>();
class attribute
How do I retrieve all categories together with their attributes because I am trying 'from category' but it is not working
Category Mapping File:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Dec 16, 2010 8:37:02 AM by Hibernate Tools 3.4.0.Beta1 -->
<hibernate-mapping>
<class name="com.BiddingSystem.Models.Category" table="CATEGORY">
<id name="CategoryId" type="long">
<column name="CATEGORYID" />
<generator class="native" />
</id>
<property name="CategoryName" type="java.lang.String">
<column name="CATEGORYNAME" />
</property>
<many-to-one name="ParentCategory" class="com.BiddingSystem.Models.Category">
<column name="PARENT_CATEGORY_ID" />
</many-to-one>
<set name="SubCategory" lazy="false" cascade="all-delete-orphan" inverse="true">
<key>
<column name="PARENT_CATEGORY_ID" />
</key>
<one-to-many class="com.BiddingSystem.Models.Category" />
</set>
<set name="AllAttributes" table="ATTRIBUTE" inverse="false" lazy="true" cascade="all">
<key>
<column name="CATEGORYID" />
</key>
<one-to-many class="com.BiddingSystem.Models.Attribute" />
</set>
</class>
</hibernate-mapping>
Attribute Mapping File:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Dec 16, 2010 5:25:09 AM by Hibernate Tools 3.4.0.Beta1 -->
<hibernate-mapping>
<class name="com.BiddingSystem.Models.Attribute" table="ATTRIBUTE">
<id name="AttributeId" type="long">
<column name="ATTRIBUTEID" />
<generator class="native" />
</id>
<property name="AttributeName" type="java.lang.String">
<column name="ATTRIBUTENAME" />
</property>
<set name="Options" table="ATTRIBUTEOPTION" inverse="false" cascade="all">
<key>
<column name="ATTRIBUTEID" />
</key>
<one-to-many class="com.BiddingSystem.Models.AttributeOption" />
</set>
</class>
</hibernate-mapping>
You have mapped the association with lazy="true". This tells hibernate that by default, a category's attributes should only be loaded from the database when they are actually accessed, in contrast to lazy="false" which would instruct hibernate to load the attributes whenever it loads a category. However, the directive in the mapping file affects all queries.
In case you want it only for a particular query, check out
http://docs.jboss.org/hibernate/core/3.5/reference/en/html/queryhql.html#queryhql-joins :
A "fetch" join allows associations or
collections of values to be
initialized along with their parent
objects using a single select. This is
particularly useful in the case of a
collection. It effectively overrides
the outer join and lazy declarations
of the mapping file for associations
and collections. See Section 20.1,
“Fetching strategies” for more
information.
from Cat as cat
inner join fetch cat.mate
left join fetch cat.kittens
A fetch join does not usually need to
assign an alias, because the
associated objects should not be used
in the where clause (or any other
clause). The associated objects are
also not returned directly in the
query results. Instead, they may be
accessed via the parent object. The
only reason you might need an alias is
if you are recursively join fetching a
further collection:
from Cat as cat
inner join fetch cat.mate
left join fetch cat.kittens child
left join fetch child.kittens
The fetch construct cannot be used in
queries called using iterate() (though
scroll() can be used). Fetch should be
used together with setMaxResults() or
setFirstResult(), as these operations
are based on the result rows which
usually contain duplicates for eager
collection fetching, hence, the number
of rows is not what you would expect.
Fetch should also not be used together
with impromptu with condition. It is
possible to create a cartesian product
by join fetching more than one
collection in a query, so take care in
this case. Join fetching multiple
collection roles can produce
unexpected results for bag mappings,
so user discretion is advised when
formulating queries in this case.
Finally, note that full join fetch and
right join fetch are not meaningful.
When I use hibernate eclipse plugin to generate java class from my table, the private field name is the same with my table name. Is there a way for me to make it to be the same with my column name instead?
For example:
table: User
column : name (string)
column : homeAddressId (fk to addressTable)
The generated class right now is:
User{
private String name;
private Address address;
}
I want it to be:
User{
private String name;
private Address homeAddress;
}
Is there a settings to do that?
Thanks very much for your help.
there can be problem in the understanding between you and hibernate. Actually, what i see, there is a foreign key with other table which is Address, not homeAddress.
can you also post the other table(Address) structure.
as if the other table name is Address then hibernate plugin is bond to create create attribute with name address, as i feel plugin doesn't have intelligence of its own.
Before anything, your domain should be the way you want it. If you need to make more changes to the mapping (ORM), you might need to do it in your hibernate-conf.xml. The generated class and the current class is the same. For example the user.xml will be something like this:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="User" table="ADMIN_USER_TBL">
<id name="id" type="string" column="ADMIN_USER_ID">
<generator class="assigned" />
</id>
<property name="name" column="FIRST_NAME" />
...
</class>
</hibernate-mapping>
Then, have the mapping for the address:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="Address" table="ADDRESS_TBL">
<id name="id" type="string" column="ADMIN_USER_ID">
<generator class="assigned" />
</id>
<property name="address" column="ADDRESS1" />
<property name="address2" column="ADDRESS2" />
<property name="city" column="ADDRESS_CITY" />
<property name="state" column="ADDRESS_STATE" />
<property name="zip" column="ADDRESS_ZIP" />
...
</class>
</hibernate-mapping>
Let me know if that helps! ;)
Hello guys sorry if the question looks stupid to you.
i have 3 tables currency (id | name) language (id| name | description) transaction (id|amount|languageId | currencyid)
so i want to insert into the transaction but making sure that it doesn't insert unknown language or currency (meaning it shouldn't insert to messagetemplate if there is no existing parent language and currency)
here are my mapping files
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.myproject.model">
<class name="Transaction" table="transaction">
<id name="id">
<generator class="native"/>
</id>
<property column="amount" name="amount" type="String"/>
<many-to-one class="CurrencyImpl" column="currency" name="currency"/>
<many-to-one class="LanguageImpl" column="language" name="language"/>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.myproject.model">
<class name="Currency" table="currency">
<id name="id">
<generator class="native"/>
</id>
<property column="currency_name" name="name" type="String"/>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.myproject.model">
<class name="Language" table="language">
<id name="id">
<generator class="native"/>
</id>
<property column="language_name" name="name" type="String"/>
<property column="language_description" name="description" type="String"/>
</class>
</hibernate-mapping>
with this current mapping it's seems not to be the case.how to achieve that? thanks a lot for reading
You're many to one references CurrencyImpl and LanguageImpl, but those classes are not mapped, only the (presumably corresponding) interfaces. I suggest you begin by creating and mapping only concrete classes and get that working before trying to mess about with mapping interfaces.