I'm facing a problem with class mapping in hibernate.
I'm trying to make a many-to-one relationship using a composite-id.
and the mapping is returning
Repeated column in mapping for entity:
br.com.is.isenterprise.cre.model.ClienteRegraIcmsMap column: EMPRESAID
(should be mapped with insert="false" update="false")
but if I set the many-to-one relationship to insert =" false " and update =" false I can not insert the id of regraIcmsSubistituta in the database.
follows the hbm files.
RegraIcms.hbm.xml
<hibernate-mapping package="br.com.is.isenterprise.efi.model">
<class name="RegraIcms" table="REGRAICMS">
<composite-id name="cid" class="br.com.is.isenterprise.efi.model.RegraIcmsId">
<key-property name="empCod" type="integer" column="EMPCOD"/>
<key-property name="idRegraIcms" type="integer" column="IDREGRAICMS"/>
</composite-id>
<property name="descricao" type="string" column="DESCRICAO" access="field"/>
<property name="aplicacao" type="integer" column="APLICACAO" access="field"/>
</class>
</hibernate-mapping>
ClienteRegraIcmsMapId.hbm.xml
<class name="ClienteRegraIcmsMap" table="CLIENTEREGRAICMSMAP">
<composite-id name="cid" class="br.com.is.isenterprise.cre.model.ClienteRegraIcmsMapId">
<key-many-to-one name="cliente" column="CLIENTEID" class="br.com.is.isenterprise.cre.model.Cliente" access="field" lazy="false"/>
<key-many-to-one name="regraIcms" class="br.com.is.isenterprise.efi.model.RegraIcms" access="field" lazy="false">
<column name="EMPRESAID"/>
<column name="REGRAICMSID"/>
</key-many-to-one>
</composite-id>
<version name="versao" type="integer" column="VERSAO"/>
<many-to-one name="regraIcmsSubstituta" class="br.com.is.isenterprise.efi.model.RegraIcms" access="field" lazy="false">
<column name="EMPRESAID"/>
<column name="REGRAICMSSUBSTITUTAID"/>
</many-to-one>
</class>
</hibernate-mapping>
You're trying to use the same column (EMPRESAID) for two different things, the primary key as well as the many-to-one relation.
That's not gonna work (except with insertable = "false", as you mentioned)
If it's possible use a separate column for EMPRESAID in one of the mappings.
Related
Say I have three tables in a many-to-many: user, group, and user_in_group. The structure of the many-to-many is:
user_id BIGINT
group_id BIGINT
generate_table TINYINT
Which should result in:
public UserInGroup(UserInGroupId id = new UserInGroupId(user_id, group_id),
User user,
Group group,
boolean generateTable)
But instead, it results in:
public UserInGroup(UserInGroupId id = new UserInGroupId(user_id, group_id),
Group group,
User user,
boolean generateTable)
I thought it might be that the foreign key for group was created before the foreign key for user, but I swapped the foreign keys and it make no difference.
Here is my UserInGroup.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 Aug 1, 2014 10:06:06 AM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="com.my.project.UserInGroup" table="user_in_group" catalog="project">
<composite-id name="id" class="com.my.project.UserInGroupId">
<key-property name="UserId" type="long">
<column name="user_id" />
</key-property>
<key-property name="GroupId" type="long">
<column name="group_id" />
</key-property>
</composite-id>
<many-to-one name="Group" class="com.my.project.Group" update="false" insert="false" fetch="select">
<column name="group_id" not-null="true" />
</many-to-one>
<many-to-one name="User" class="com.my.project.User" update="false" insert="false" fetch="select">
<column name="user_id" not-null="true" />
</many-to-one>
<property name="generateTable" type="boolean">
<column name="generate_table" not-null="true" />
</property>
</class>
</hibernate-mapping>
The order of the properties in the generated constructors corresponds to the order of the properties within the XML Mapping.
In the mapping for the composite key, the userId is first, then the groupId. Hence you get new UserInGroupId(user_id, group_id). For the many-to-one references, it is vice-versa - the reference to the Group is stated first, then the reference to the User.
You can simply change the XML and switch the order of the many-to-one references:
<many-to-one name="User" class="com.my.project.User" update="false" insert="false" fetch="select">
<column name="user_id" not-null="true" />
</many-to-one>
<many-to-one name="Group" class="com.my.project.Group" update="false" insert="false" fetch="select">
<column name="group_id" not-null="true" />
</many-to-one>
Since the XML is generated from reverse engeneering, the database that you reverse engeneer probably returns the two foreign keys in the order that you see in the generated XML. If you do not want to manually change the XML, you should check, if you can modify the source database to return the columns in your desired order.
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 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" />
I have 3 tables:
Account
{
Long account_id; // primary key, alternate key field 1
Long client_id; // alternate key field 2
...
}
Admin
{
Long office_id; // primary key field 1
Long account_id; // primary key field 2
Long client_id;
}
Office
{
Long office_id; // primary key
...
}
So the Admin table references Account table by alternate key (of account_id, client_id). I try to write mapping for it but cant understand how.
I have now:
<class name="Account" table="Account">
<id name="id">
<column name="account_id" not-null="true"/>
</id>
<properties name="account_ak1" unique="true">
<property name="id" column="account_id" insert="false" update="false"/>
<property name="client" column="client_id" insert="false" update="false"/>
</properties>
<many-to-one name="client" class="Client" column="client_id" lazy="false" fetch="join"/>
...
</class>
<class name="Admin">
<composite-id name="id" class="KeyPair">
<key-many-to-one name="t1" class="Office" column="office_id" lazy="false"/>
<key-many-to-one name="t2" class="Account" lazy="false" column="account_id"/>
</composite-id>
<many-to-one name="account" class="Account" not-null="true" insert="false" update="false" lazy="false" fetch="join" property-ref="account_ak1">
<column name="account_id"/>
<column name="client_id"/>
</many-to-one>
</class>
The problem is that i cant set client_id in sql update/insert this way and i cant set only account_id to insert/update false neither within composite-id nor within many-to-one.
Also, i tried to include all the fields of Account in primary key.
<composite-id name="id" class="KeyPair">
<key-many-to-one name="t1" class="Office" column="office_id" lazy="false"/>
<key-many-to-one name="t2" class="Account" lazy="false"/>
<column name="account_id"/>
<column name="client_id"/>
</key-many-to-one>
</composite-id>
but key-many-to-one can reference only primary key of Account and does not accept property-ref.
How to solve this?
I have one entity called ProductTemplate with the following hibernate mapping
<hibernate-mapping default-cascade="none">
<class name="com.stackoverflow.ProductTemplateImpl" table="PRODUCT_TEMPLATE" dynamic-insert="false" dynamic-update="false">
<composite-id name="productTemplatePk" class="com.stackoverflow.product.ProductTemplatePK">
<key-property name="templateType" type="java.lang.String">
<column name="TEMPLATE_ID" sql-type="VARCHAR2(255)" not-null="true"/>
</key-property>
<key-many-to-one name="product" class="com.stackoverflow.ProductImpl" >
<column name="PROD_ID"/>
</key-many-to-one>
</composite-id>
</class>
</hibernate-mapping>
where ProductTemplatePK is a normal java Primary key class.
and another entity called Product with the following hibernate mapping:
<hibernate-mapping default-cascade="none">
<class name="com.stackoverflow.ProductImpl" table="PRODUCT" dynamic-insert="false" dynamic-update="false">
<id name="id" type="java.lang.String" unsaved-value="null">
<column name="PROD_ID" sql-type="VARCHAR2(255)"/>
<generator class="assigned">
</generator>
</id>
<property name="state" type="java.lang.String">
<column name="PROD_STATE" not-null="true" unique="false"/>
</property>
<property name="nameEn" type="java.lang.String">
<column name="PROD_NAME_EN" not-null="true" unique="false"/>
</property>
</class>
</hibernate-mapping>
Now if I tried to retrieve all productTemplates based on the productId I can do it using the following hibernate criteria:
Criteria productTemplateCriteria = this.getSession().createCriteria(ProductTemplate.class);
productTemplateCriteria.add(Restrictions.in("productTemplatePk.product.id", "1"));
but I don't know how to retrieve those templates based on the product.nameEn as the following code:
Criteria productTemplateCriteria = this.getSession().createCriteria(ProductTemplate.class);
productTemplateCriteria.add(Restrictions.in("productTemplatePk.product.nameEn", "Ali"));
generates the following error:
Caused by: org.hibernate.QueryException: could not resolve property: productTemplatePk.product.nameEn of: com.stackoverflow.ProductTemplateImpl.
so how can I query an entity property that is mapped as part of a composite primary key ?
I manged to solve this by simple HQL query as I didn't find any way to do it using hibernate API
this is the HQL query I used:
from com.stackoverflow.ProductTemplateImpl productTemplate
where productTemplate.productTemplatePk.product.state not in (:productStates)
But I'm still interested to know if there is any Hibernate API combination that can do it.
I was not able to get deeper than 2 levels except for ids when specifying property names in criteria. Try using explicit join with alias:
Criteria crit = this.getSession().createCriteria(ProductTemplate.class);
crit.addAlias("productTemplatePk.product","p")
.add(Restrictions.in("p.nameEn", "Ali"));