I use Spring 3 and hibernate 3.6.3.Final. I have to entities A and B. The hbm files are:
A.hbm.xml
<hibernate-mapping>
<class name="com.A" table="A" >
<id name="A_Id" type="string">
<column name="Id" length="100" />
<generator class="foreign">
<param name="property">B</param>
</generator>
</id>
<one-to-one name="B" class="B" constrained="true" fetch="select" ></one-to-one>
<property>...</property>
</class>
</hibernate-mapping>
and B.hbm.xml
<hibernate-mapping>
<class name="com.B" table="B">
<id name="B_Id" type="string">
<column name="Id" length="32" />
<generator class="assigned" />
</id>
...
<one-to-one name="some_A" class="com.A" lazy="proxy"></one-to-one> // FIRST
<one-to-one name="other_A" class="com.A" lazy="proxy" cascade="all" > // SECOND
<formula>other_BSRC_REG_REP_MESSAGE_ID</formula>
</one-to-one>
</class>
</hibernate-mapping>
From #Service I use the following code to get entity B by id:
getHibernateTemplate().get(getEntityClass(), id)
I enabled the show_sql mode in hibernate in order to check if my lazy loading works fine. Unfortunately I don't understand them
When either FIRST or SECOND line is commented out hibernate shows exactly one query (where all of the one-to-one associations are present as join),
When both FIRST and SECOND lines are uncommented hibernate shows two queries, one to get B and second to get an A entity.
Why this happens? Is it because all of the one-to-one association can't be lazy loaded so either they are eagerly loaded as a separate query or "joined" to the original query? If so, why hibernate didn't joined on the A table twice?
Related
I am new to propel. There doesn't appear to be a version command built in, but composer shows propel2 in my description.
I reverse engineered my scheme and models from the database then took six months off the project, came back, remastered the database directly, deleted the generated-classes, and the generated-reversed-database.
I then ran
propel reverse "mysql:host=localhost;dbname=MyVanLog;user=**;password=**"
When that completed I opened my schema.xml file and visually verified that the fuel price column no longer exists.
<table name="LogEntries" idMethod="native" phpName="Logentries">
<column name="LogEntryId" phpName="Logentryid" type="INTEGER" primaryKey="true" autoIncrement="true" required="true"/>
<column name="UserId" phpName="Userid" type="INTEGER" primaryKey="true" required="true"/>
<column name="RvId" phpName="Rvid" type="INTEGER" primaryKey="true" required="true"/>
<column name="Title" phpName="Title" type="VARCHAR" size="45" required="true"/>
<column name="Description" phpName="Description" type="CLOB"/>
<column name="Longitude" phpName="Longitude" type="DECIMAL" size="10" scale="8"/>
<column name="Latitude" phpName="Latitude" type="DECIMAL" size="10" scale="8"/>
<column name="Temperature" phpName="Temperature" type="DECIMAL" size="3" scale="1"/>
<column name="Private" phpName="Private" type="VARCHAR" size="1" sqlType="bit(1)" required="true"/>
<column name="CreatedOnUTC" phpName="Createdonutc" type="TIMESTAMP" required="true"/>
<column name="ModifiedOnUTC" phpName="Modifiedonutc" type="TIMESTAMP" required="true"/>
<foreign-key foreignTable="Users" name="FK_36">
<reference local="UserId" foreign="UserId"/>
</foreign-key>
<foreign-key foreignTable="Rvs" name="FK_40">
<reference local="RvId" foreign="RvId"/>
<reference local="UserId" foreign="UserId"/>
</foreign-key>
<index name="fkIdx_36">
<index-column name="UserId"/>
</index>
<index name="fkIdx_40">
<index-column name="RvId"/>
<index-column name="UserId"/>
</index>
<vendor type="mysql">
<parameter name="Engine" value="InnoDB"/>
</vendor>
Then I run propel build to generate my models. I open my base/LogEntries file and it has all the methods to manipulate the field that is no longer there. I won't paste the entire file, but here is the get method.
/**
* Get the [fuelpriceinvalid] column value.
*
* #return string
*/
public function getFuelpriceinvalid()
{
return $this->fuelpriceinvalid;
}
Does anyone know what I missed?
I had an extra schema.xml file hanging out in the project directories that was being read instead of the one I generated causing the old fields to generate. This was likely just a mistake on my part, not a propel bug.
How do I make the Bag optional for class Test in the following pseudo hbm.xml?
<class name="Test" table="test">
<bag name="bag" table="example" cascade="all" fetch="join">
<key property-ref="key">
<column name="a_id" />
<column name="b_id" />
</key>
<element column="example_id"
type="my.myclass"/>
</bag></class>
my.mclass is a custom type (my.myclass implements org.hibernate.usertype.UserType)
In the moment if there is no fitting "test example" row in the example table I get an exception?
(I was hoping to find a kind of not-found attribute? But there is no)
What's the relationship between Test and myclass? 1 to many or many to many?
If it's 1 to many in your case, I will suggest you create separate mapping for myclass and use following mapping for Test class
<bag name="bag" table="example" inverse="true" cascade="all" fetch="join">
<key property-ref="key">
<column name="a_id" />
<column name="b_id" />
</key>
<one-to-many class="my.myclass"/>
</bag>
There are two classes A and B and hibernate mappings
<hibernate-mapping default-lazy="false">
<class name="A" table="A">
<id name="id" type="long">
<generator class="sequence"><param name="sequence">A_SEQUENCE</param></generator></id>
<set name="a" cascade="all" inverse="false" >
<key><column name="A_FK" not-null="true" /></key>
<one-to-many class="B" /></set>
</class>
</hibernate-mapping>
<hibernate-mapping default-lazy="false">
<class name="B" table="B">
<id name="id" type="long"> <column name="ID"/>
<generator class="sequence"><param name="sequence">B_SEQUENCE</param></generator></id>
</class>
</hibernate-mapping>
On the database there is a not null contraint and a foreign key constraint on the column A_FK of table B.
When I try to insert an A that contains a B I get the following error:
ORA-01400: cannot insert NULL into ("SCHEMA"."B"."A_FK")
Is it possible to insert this kind of data without having to specify the inverse=true flag? and the inverse relationship?
Not without getting rid of the way the id is generated. Can you switch how the Id is generated?
Converting the problem to a question is half the answer...
What was missing was the not-null="true" on the key of the set:
<set name="a" cascade="all" inverse="false" >
<key not-null="true"><column name="A_FK" not-null="true" /></key>
<one-to-many class="B" />
</set>
a company I am working for is using an ERP and it's legacy database is Oracle.
Until now I've used packages (oracle stored procedures) to access data but during the years the number has grown consistently and now I can't manage them anymore.
I was trying to do some experiments with Nhibernate and started mapping few tables.
All the tables have composite primary keys.
A brief description:
Table Order (table name: OCSAORH)
OCHORDN (PK) => OrderNumber
OCHAMND (PK)
OCHCOSC (PK) => Company
OCHCLII
...
Table OrderLine (table name: OCSALIN)
OCLORDN (PK) => OrderNumber
OCLAMND (PK)
OCLCOSC (PK) => Company
OCLLINN (PK) => Line Number
OCLSSEQ (PK)
OCLITMN
...
This is my mapping
Order:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="MvcOracleNhibernate"
namespace="MvcOracleNhibernate.Domain">
<class name="Order" table="OCSAORH">
<composite-id>
<key-property name="Number" column="OCHORDN"></key-property>
<key-property name="Ver" column="OCHAMND"></key-property>
<key-property name="Company" column="OCHCOSC"></key-property>
</composite-id>
<property name="CustomerCode" column="OCHCLII" type="String" length="10"></property>
<property name="Reference" column="OCHOCNO" type="String" length="25"></property>
<property name="Date" column="OCHOCDT" type="Double"></property>
<bag name="OrderLines" cascade="all-delete-orphan" generic="true" inverse="true" lazy="false">
<key>
<column name="OCLORDN" not-null="true"/>
<column name="OCLAMND" not-null="true"/>
<column name="OCLCOSC" not-null="true"/>
</key>
<one-to-many class="OrderLine" not-found="ignore"/>
</bag>
</class>
</hibernate-mapping>
OrderLine:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="MvcOracleNhibernate"
namespace="MvcOracleNhibernate.Domain">
<class name="OrderLine" table="OCSALIN">
<composite-id>
<key-property name="Number" column="OCLORDN"></key-property>
<key-property name="Ver" column="OCLAMND" ></key-property>
<key-property name="Company" column="OCLCOSC"></key-property>
<key-property name="Line" column="OCLLINN"></key-property>
<key-property name="Seq" column="OCLSSEQ"></key-property>
</composite-id>
<property name="Item" column="OCLITMN" type="String" length="19"></property>
<property name="Quantity" column="OCLQTYP" type="Double"></property>
</class>
</hibernate-mapping>
With these mappings everything works fine; I can load an order and the lazy loading loads my lines.
While reading some documentation I've noticed that I haven't defined the many-to-one relation so I've added this:
<many-to-one name="Order" class="Order" lazy="proxy">
<column name="OCHORDN" not-null="true"/>
<column name="OCHAMND" not-null="true"/>
<column name="OCHCOSC" not-null="true"/>
</many-to-one>
to the OrderLine mapping file.
Now if I run my test app the order is loaded properly but the order lines are not loaded.
I get a {NHibernate.ADOException} = {"could not initialize a collection: ... }
I've tried to investigate and noticed that the generated query to retrieve the rows is wrong. This is the SQL:
SELECT
orderlines0_.OCLORDN as OCLORDN1_,
orderlines0_.OCLAMND as OCLAMND1_,
orderlines0_.OCLCOSC as OCLCOSC1_,
orderlines0_.OCLLINN as OCLLINN1_,
orderlines0_.OCLSSEQ as OCLSSEQ1_,
orderlines0_.OCLORDN as OCLORDN13_0_,
orderlines0_.OCLAMND as OCLAMND13_0_,
orderlines0_.OCLCOSC as OCLCOSC13_0_,
orderlines0_.OCLLINN as OCLLINN13_0_,
orderlines0_.OCLSSEQ as OCLSSEQ13_0_,
orderlines0_.OCLITMN as OCLITMN13_0_,
orderlines0_.OCLQTYP as OCLQTYP13_0_,
orderlines0_.OCHORDN as OCHORDN13_0_,
orderlines0_.OCHAMND as OCHAMND13_0_,
orderlines0_.OCHCOSC as OCHCOSC13_0_
FROM OCSALIN orderlines0_
WHERE
orderlines0_.OCLORDN=?
and orderlines0_.OCLAMND=?
and orderlines0_.OCLCOSC=?
As you can notice the last 3 fields of the select (those with the prefix OCH instead of OCL) aren't members of the OCSALIN table; they are the key of the OCSAORH.
After 1 days spent reading documentation and examples I can't figure out what I am doing wrong.
Is there anybody there who can try to help?
This is the expected behavior. You're defining the foreign keys in your many-to-one mapping. So the columns need to exist in the object you're defining.
I think you want this
<many-to-one name="Order" class="Order" lazy="proxy">
<column name="OCLORDN" not-null="true"/>
<column name="OCLAMND" not-null="true"/>
<column name="OCLCOSC" not-null="true"/>
</many-to-one>
I am a newbie for Hibernate. Hope you guys can help me debug below error which really make me crazy.
I got a table called CONTENT_WORKGROUP which will map to another table called CONTENT_WORKGROUP_ROLE. Below is the table structure and sample data:
CONTENT_WORKGROUP
CM_WORKGROUP_ID NUMBER(15,0)
WORKGROUP_ID NUMBER(15,0)
ROLE_ID VARCHAR2(20 BYTE)
CONTENT_WORKGROUP_ROLE
CM_WORKGROUP_ROLE_ID NUMBER(15,0)
ROLE_ID VARCHAR2(20 BYTE)
FUNCTION_ID VARCHAR2(40 BYTE)
P/S: One user workgroup can have multiple role (Creator, Admin, Approver). The function(Add, Edit, Delete) that can perform by this workgroup can be query from CONTENT_WORKGROUP_ROLE.
Sample DATA:
CONTENT_WORKGROUP
CM_WORKGROUP_ID WORKGROUP_ID ROLE_ID
1 136 Creator
2 137 Administrator
3 136 Administrator
CONTENT_WORKGROUP_ROLE
CM_WORKGROUP_ROLE_ID ROLE_ID FUNCTION_ID
1 Creator Copy
2 Creator Edit
3 Creator Delete
4 Creator Add
5 Administrator Edit
6 Administrator Approve
7 Administrator Reject
However, I am getting the error when I get the SET of ContentWorkgroupRole hold by particular workgroup.
[11/23/10 15:28:56:053 SGT] 00000039 SystemOut O [23/11/2010 15:28:56.053] ERROR JDBCExceptionReporter - ORA-01722: invalid number
[11/23/10 15:28:56:100 SGT] 00000039 ServletWrappe E SRVE0068E: Uncaught exception thrown in one of the service methods of the servlet: action. Exception thrown : javax.servlet.ServletException: could not initialize a collection: [corp.celcom.next.infochannel.model.ContentWorkgroup.contentWorkgroupRole#1]
Below is my hibernate mapping file:
ContentWorkgroup.hbm.xml
<hibernate-mapping>
<class name="corp.celcom.next.infochannel.model.ContentWorkgroup" table="CM_WORKGROUP" >
<id name="cmWorkgroupId" type="long">
<column name="CM_WORKGROUP_ID" precision="15" scale="0" />
CM_WORKGROUP
CM_WORKGROUP_ID
ContentWorkgroupRole.hbm.xml
<hibernate-mapping>
<class name="corp.celcom.next.infochannel.model.ContentWorkgroupRole" table="CM_WORKGROUP_ROLE" >
<id name="cmWorkgroupRoleId" type="long">
CM_WORKGROUP_ROLE_ID
CM_WORKGROUP_ROLE
<many-to-one name="contentWorkgroup" class="corp.celcom.next.infochannel.model.ContentWorkgroup" fetch="select">
<column name="ROLE_ID" precision="15" scale="0" />
</many-to-one>
In my ACTION class, the above mentioned error occured on this line:
Iterator iter = cw.getContentWorkgroupRole().iterator();
for(ContentWorkgroup cw : contentWorkgroupList)
{
Iterator iter = cw.getContentWorkgroupRole().iterator();
while (iter.hasNext()) {
ContentWorkgroupRole role = (ContentWorkgroupRole) iter.next();
if (role.getFunctionId().equalsIgnoreCase(Constant.ADD))
myForm.setAllowAdd(true);
if (role.getFunctionId().equalsIgnoreCase(Constant.EDIT))
myForm.setAllowEdit(true);
if (role.getFunctionId().equalsIgnoreCase(Constant.DELETE))
myForm.setAllowDelete(true);
}
}
The weird part is when I change the ROLE_ID to Integer/Long (i.e 1-Creator, 2-Administrator), instead of using String, it work fine! I couldn't understand why and what the problem on my code.
Thanks for you help. It took me 1 day already to cope with this error. Thanks!
Sorry, the display seem got abit problem. I write again here:
ContentWorkgroup.hbm.xml
<hibernate-mapping>
<class name="corp.celcom.next.infochannel.model.ContentWorkgroup" table="CM_WORKGROUP" >
<id name="cmWorkgroupId" type="long">
<column name="CM_WORKGROUP_ID" precision="15" scale="0" />
<generator class="corp.celcom.next.util.MultipleTableGenerator" >
<param name="KEYTABLE_VALUE">CM_WORKGROUP</param>
<param name="KEYCOLUMN_VALUE">CM_WORKGROUP_ID</param>
</generator>
</id>
<property name="workgroupId" type="long">
<column name="WORKGROUP_ID" precision="15" scale="0" not-null="true" />
</property>
<property name="srId" type="string">
<column name="SR_ID" length="15" not-null="true" />
</property>
<property name="contentCategoryId" type="string">
<column name="CONTENT_CATEGORY_ID" length="40" not-null="true" />
</property>
<property name="roleId" type="string">
<column name="ROLE_ID" length="20" not-null="true" />
</property>
<set name="contentWorkgroupRole" table="CM_WORKGROUP_ROLE" inverse="true">
<key>
<column name="ROLE_ID" length="20" not-null="true" />
</key>
<one-to-many class="corp.celcom.next.infochannel.model.ContentWorkgroupRole" />
</set>
</class>
ContentWorkgroupRole.hbm.xml
<hibernate-mapping>
<class name="corp.celcom.next.infochannel.model.ContentWorkgroupRole" table="CM_WORKGROUP_ROLE" >
<id name="cmWorkgroupRoleId" type="long">
<column name="CM_WORKGROUP_ROLE_ID" precision="15" scale="0" />
<generator class="corp.celcom.next.util.MultipleTableGenerator">
<param name="KEYCOLUMN_VALUE">CM_WORKGROUP_ROLE_ID</param>
<param name="KEYTABLE_VALUE">CM_WORKGROUP_ROLE</param>
</generator>
</id>
<many-to-one name="contentWorkgroup" class="corp.celcom.next.infochannel.model.ContentWorkgroup" fetch="select">
<column name="ROLE_ID" precision="15" scale="0" />
</many-to-one>
<property name="menuId" type="string">
<column name="MENU_ID" length="40" not-null="true" />
</property>
<property name="functionId" type="string">
<column name="FUNCTION_ID" length="40" not-null="true" />
</property>
In my ACTION class, the above mentioned error occured on this line:
Iterator iter = cw.getContentWorkgroupRole().iterator();
for(ContentWorkgroup cw : contentWorkgroupList)
{
Iterator iter = cw.getContentWorkgroupRole().iterator();
while (iter.hasNext()) {
ContentWorkgroupRole role = (ContentWorkgroupRole) iter.next();
if (role.getFunctionId().equalsIgnoreCase(Constant.ADD))
myForm.setAllowAdd(true);
if (role.getFunctionId().equalsIgnoreCase(Constant.EDIT))
myForm.setAllowEdit(true);
if (role.getFunctionId().equalsIgnoreCase(Constant.DELETE))
myForm.setAllowDelete(true);
}
}