I have a table Project with fields
ID
PROJECT_BASELINE_ATTRIBUTES_ID (FK for table PROJECT_BASELINE_ATTR)
This table has the following mapping
<hibernate-mapping package="com.initech.db.model">
<class name="com.initech.db.model.Project" table="PROJECT">
<id name="id" column="id" type="java.lang.Long">
<meta attribute="use-in-tostring">true</meta>
<generator class="sequence">
<param name="sequence">PROJECT_ID_SEQ</param>
</generator>
</id>
<many-to-one name="projectBaselineAttributes" column="PROJECT_BASELINE_ATTRIBUTES_ID" class="com.initech.db.model.ProjectBaselineAttributes" cascade="all" not-null="true">
<meta attribute="use-in-tostring">true</meta>
</many-to-one>^
</class>
</hibernate-mapping>
The respective Project.java class has the fields
private Long id;
private ProjectBaselineAttributes projectBaselineAttributes;
Furthermore, I have a table PROJECT_BASELINE_ATTR, containing the field
ID
The Hibernate mapping:
<hibernate-mapping package="com.initech.db.model">
<class name="com.initech.db.model.ProjectBaselineAttributes" table="PROJECT_BASELINE_ATTR">
<id name="id" column="id" type="java.lang.Long">
<generator class="sequence">
<param name="sequence">PRO_BASE_ATTR_ID_SEQ</param>
</generator>
</id>
<set name="projects" table="PROJECT" inverse="true" lazy="true" fetch="select">
<key>
<column name="PROJECT_BASELINE_ATTRIBUTES_ID" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.initech.db.model.Project" />
</set>
</class>
</hibernate-mapping>
The respective ProjectBaselineAttributes.java class has the fields
private Long id;
private Set projects = new HashSet();
The current mapping is not ideal, as the relationship between the two tables is actually one-to-one, but in the ProjectBaselineAttributes I have a set of Projects, even though there is always one Projet for one ProjectBaseLineattributes. What should the mapping look like for ProjectBaselineAttributes so that I can get the associated Project "singularly", i.e. so that the class ProjectBaselineAttributes.java would look like this:
private Long id;
private Project project;
Here's the section of the Hibernate documentation which details how to map such a bidirectional one-to-one association using a foreign key.
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<many-to-one name="address"
column="addressId"
unique="true"
not-null="true"/>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
<one-to-one name="person"
property-ref="address"/>
</class>
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
You can try the below mappings as told in this example.
In the parent bean,
<one-to-one name="one2oneSubA1" class="com.manu.hibernate.mappings.domain.ASub1" cascade="all"
property-ref="parent"/>
In the child bean,
<many-to-one name="parent"
class="com.manu.hibernate.mappings.domain.AMain" column="a_id"
unique="true" cascade="save-update" />
Related
I'm adding ResourcePermission to the object Report. Each Query object can have in a one-to-one relationship. A Query extends Resource and has ResourcePermission's in a one-to-many (one Query to many Permissions).
I need to add the same property to the Report object associated with the Query because it can have different permissions. When I add the list and the map the one Query to many Permission relationship I get
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.bio.ResourcePermission column: resource_id (should be mapped with insert="false" update="false")
Which I am not understanding why, the Report does not extend Query or Resource and therefore it isn't mapped twice. Can a table just not be the many for multiple one-to-many relationships?
<class name="com.bio.Report" table="REPORT">
<id name="id" type="long" column="id">
<generator class="foreign">
<param name="property">query</param>
</generator>
</id>
<property name="name" column="name"/>
<!--Trying to add this list mapping breaks it-->
<bag name="permissions" table="RESOURCE_PERMISSION">
<key column="resource_id" not-null="true"/>
<one-to-many class="com.bio.ResourcePermission"/>
</bag>
<!-- This query extends Resource-->
<one-to-one name="query" class="com.bio.Query" />
</class>
This is the original item that had ResourcePermissions
<class name="com.bio.Resource" table="RESOURCE">
<id name="id" type="long" column="id">
<generator class="native">
<param name="sequence">SEQ_RESOURCE_AUTO</param>
</generator>
</id>
<bag name="permissions" table="RESOURCE_PERMISSION" lazy="true" batch-size="50" cascade="all-delete-orphan">
<key column="resource_id" not-null="true"/>
<one-to-many class="com.bio.ResourcePermission"/>
</bag>
</class>
The Permission mapping
<class name="com.bio.ResourcePermission" table="RESOURCE_PERMISSION">
<id name="id" type="long" column="id">
<generator class="native">
<param name="sequence">SEQ_RES_PERM_AUTO</param>
</generator>
</id>
<property name="canEdit" column="edit"/>
<property name="canView" column="can_view"/>
<property name="canRun" column="run"/>
<property name="everyone" column="everyone"/>
</class>
I had to set inverse="true" on the Report mapping since the ReportPermission will be responsible for the relationship.
<bag name="permissions" table="RESOURCE_PERMISSION" inverse="true">
<key column="resource_id" not-null="true"/>
<one-to-many class="com.bio.ResourcePermission"/>
</bag>
I am a new bie to the world of hibernate could you please advise , I was going through one to one relationship in Hibernate,
As per my analysis , one to one hibernate relationships can be established by three ways..
1)Through Join concept
2)Same primary key in both the tables
3)Primary key and foriegn key relationship in both the tables
Please advise , the above three ways to achieve the one to one mapping is correct or I am missing something then please advise, and also please advise that the below hbm mapping files that I am using are correct one.if not then please advise.
1) Through Join concept :-
One way to achieve to one to one relationship is by joining concept , following xml is being used for that
<hibernate-mapping>
<class name="mypack.Person" table="person21">
<id name="personId" type="int">
<generator class="increment">
</generator>
</id>
<property name="name"/>
<join table="personAddress">
<key column="personId"/>
<many-to-one name="address" class="mypack.Address" column="addressId" unique="true" cascade="all"/>
</join>
</class>
<class name="mypack.Address" table="address21">
<id name="id" column="addressId" type="int">
<generator class="increment"/>
</id>
<property name="city"/>
<property name="state"/>
</class>
</hibernate-mapping>
2) Same primary key in both the tables :-
Using same primary key in both the tables , following hbm is being used for that
<class name="mypack.Address" table="address31">
<id name="id" column="addressId" type="int">
<generator class="increment"/>
</id>
<property name="city"/>
<property name="state"/>
</class>
<class name="mypack.Person" table="person31">
<id name="personId" type="int">
<generator class="foreign">
<param name="property">address</param>
</generator>
</id>
<property name="name"/>
<one-to-one name="address" class="mypack.Address"/>
</class>
</hibernate-mapping>
3)Primary key and foriegn key relationship in both the tables :-
Primary key in one table and foriegn key in another table. below is the hbm for this
<hibernate-mapping>
<class name="mypack.Person">
<id name="personId" type="int">
<generator class="increment"/>
</id>
<property name="name"/>
<many-to-one name="address" class="mypack.Address" column="addressId" unique="true" cascade="all"/>
</class>
<class name="mypack.Address">
<id name="id" column="addressId" type="int">
<generator class="increment"/>
</id>
<property name="city"/>
<property name="state"/>
</class>
</hibernate-mapping>
folks please advise.
I really think that join table is overkill here for a one-to-one mapping. For the other 2 solutions, please take a look at the following Hibernate documentation, everything is explained : http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/mapping.html#mapping-declaration-onetoone.
For your second mapping (primary key association), both entities need to define a one-to-one mapping and one side of the relation also needs to specify the attribute constrained="true".
This is how I would write your second mapping :
<class name="mypack.Person" table="PERSONS">
<id name="id" type="int" column="PERSON_ID">
<generator class="increment"/>
</id>
<property name="name" type="string" column="NAME"/>
<one-to-one name="address" class="mypack.Address" cascade="all"/>
</class>
<class name="mypack.Address" table="ADDRESSES">
<id name="id" type="int" column="ADDRESS_ID">
<generator class="foreign">
<param name="property">address</param>
</generator>
</id>
<property name="city" type="string" column="CITY"/>
<property name="state" type="string" column="STATE"/>
<one-to-one name="person" class="mypack.Person" constrained="true"/>
</class>
I have domain Classes - User, Role, Group, Group Role
User Domain
private long id,
private String userName,
private String password,
Set<Role> roles = new HashSet<Role>();
User.hbm.xml
<hibernate-mapping package="uk.co.jmr.sdp.domain">
<class name="User" table="user">
<id name="id" unsaved-value="-1">
<generator class="native"/>
</id>
<property name="userName" column="user_name"/>
<property name="password" column="password"/>
<property name="emailId" column="email_id"/>
<set name="roles" table="user_role" lazy="false" cascade="all">
<key column="user_id"/>
<many-to-many column="role_id" class="Role" fetch="join"/>
</set>
<set name="groupRoles" table="user_grouprole" lazy="false" cascade="all">
<key column="user_id"/>
<many-to-many column="group_role_id" class="GroupRole" fetch="join"/>
</set>
</class>
</hibernate-mapping>
I have user_grouprole table as a join table for an User and Set of grouproles
I have user_role table as a join table for an user and set of roles
Group Domain
private long id;
private String groupName;
private Set<Role> roles = new HashSet<Role>();
Group.hbm.xml
<hibernate-mapping package="uk.co.jmr.sdp.domain">
<class name="Group" table="group">
<id name="id" unsaved-value="-1">
<generator class="native"/>
</id>
<property name="groupName" column="group_name"></property>
<set name="roles" table="group_role" lazy="false" cascade="all">
<key column="group_id"/>
<many-to-many column="role_id" class="Role" fetch="join"/>
</set>
GroupRole
private long id;
private Role role;
private Group group;
GroupRole.hbm.xml
<class name="GroupRole" table="group_role">
<id name="id" unsaved-value="-1">
<generator class="native"/>
</id>
<many-to-one name="role" class="uk.co.jmr.sdp.domain.Role"
column="role_id" lazy="false" not-null="true" />
<many-to-one name="group" class="uk.co.jmr.sdp.domain.Group"
column="group_id" lazy="false" not-null="true" />
</class>
</hibernate-mapping>
When I try to test with a main class, I get a mapping error like a hibernate mapping error like
Foreign key (FK5110401A8398947:user_grouprole [group_role_id])) must have same number of columns as the referenced primary key (group_role [group_id,role_id])
What is this error? Why I get this error? What should I do to rectify this error??? Any Solutions ? Can anyone explain what is this error?
Thanks in Advance
Your error is telling that your table USER contains a foreign key on a column named GROUP_ROLE_ID, but your referenced table, GROUP_ROLE, defines it's primary key with two columns ROLE_ID and GROUP_ID, which by the way is very common for relationship tables.
Seems to me that the only reason that you are mapping GroupRole is because you need it in your User entity. Well, if your domain model is really correct, then you need to think about how you want to synchronize your User's FK and GroupRole's PK. For that you might:
Create a PK object for your composite key or define your ID's correctly in your mappings;
Change your PK definition in GroupRole table.
Best regards.
I'm using Java 1.6, Hibernate 3.1, MySQL 5.5, XML mapping. I have two tables, partner and partner_http_account. I'll just show you the relevant fields.
partner:
partnerid dec(22,0) [primary key]
partner_http_account:
partnerhttpacctid dec(22,0) [primary key]
partnerid dec(22,0) [foreign key]
Here's the XML mapping:
<class name="com.rc.model.partner.Partner" table="partner" mutable="true">
<id name="partnerId" type="int">
<column name="partnerid" scale="10" precision="0" not-null="true" unique="true" sql-type="int unsigned"/>
<generator class="com.rc.model.jdbc.sequence.MexpIdentifierGenerator">
<param name="sequence">seq_partnerid</param>
<param name="idDataType">int</param>
</generator>
</id>
...
<one-to-one name="partnerHTTPAccount" class="com.rc.model.partner.PartnerHTTPAccount" lazy="false"
foreign-key="partnerid" cascade="all"/>
</class>
<class name="com.rc.model.partner.PartnerHTTPAccount" table="partner_http_account">
<id name="partnerHttpAcctId" type="int">
<column name="partnerhttpacctid" scale="10" precision="0" not-null="true" unique="true" sql-type="int unsigned"/>
<generator class="com.rc.model.jdbc.sequence.MexpIdentifierGenerator">
<param name="sequence">seq_partnerhttpacctid</param>
<param name="idDataType">int</param>
</generator>
</id>
<many-to-one name="partner" class="com.rc.model.partner.Partner" column="partnerid"
foreign-key="partnerid" cascade="none"/>
</class>
Here is my Java code:
public List<Partner> getPartnersByDomainStartsWith(String domainStartsWith) {
Query hQuery = sessionManager.getSession().createQuery("from Partner p " +
"left outer join fetch p.partnerHTTPAccount " +
"where p.domain like :domainStartsWith||'%'");
hQuery.setString("domainStartsWith", domainStartsWith);
return hQuery.list();
}
And here is what Hibernate is generating:
select partner0_.partnerid as partnerid0_,
partnerhtt1_.partnerhttpacctid as partnerh1_1_,
...
partnerhtt1_.partnerid as partnerid104_1_,
...
from partner partner0_
left outer join partner_http_account partnerhtt1_ on partner0_.partnerid=partnerhtt1_.partnerhttpacctid
where partner0_.domain like concat(?, '%')
My problem is the generated sql query of these two tables is joining on the wrong field. It should join on partner0.partnerid=partnerhtt1.partnerid instead. Would really appreciate some insight. Thanks.
This is really well described in the Hibernate documentation:
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<many-to-one name="address"
column="addressId"
unique="true"
not-null="true"/>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
<one-to-one name="person"
property-ref="address"/>
</class>
Notice how property-ref is used, to indicate that the one-to-one is the inverse side of the association mapped by the address property.
I'm sure there must be thousands of examples demonstrating this association but I can't seem to find one anywhere.
I have a one-many relationship from Parent-Child and a many-one relationship from Child-Parent:
class Parent {
private Long id;
private String name;
private List<Child> children;
}
class Child {
private Long id;
private String name;
private Parent parent;
}
I'm expecting to end up with 2 tables that look as follows:
Parent
- id : bigint
- name : varchar
Child
- id : bigint
- parent_id : bigint
- sequence : bigint
- name : varchar
Have I got the right idea? If so does anyone know what I need to put in my mapping file so that when a parent is deleted so too are it's children.
Thanks in advance.
James
Found the solution in the end although I don't understand why I need insert="false" and update="false":
<hibernate-mapping>
<class name="foo.Parent" table="Parent">
<id name="id" type="int" column="id">
<generator class="native" />
</id>
<property name="name" type="java.lang.String" column="name" length="50" />
<list name="children" cascade="all">
<key column="parent_id" />
<index column="sequence" />
<one-to-many class="foo.Child" />
</list>
</class>
<class name="foo.Child" table="Child">
<id name="id" type="int" column="id">
<generator class="native" />
</id>
<property name="name" type="java.lang.String" column="name" length="50" />
<many-to-one name="parent" class="foo.Parent" column="parent_id" insert="false" update="false" />
</class>
</hibernate-mapping>