One-to-many mapping // how to map legacy tables (Hibernate)
I have two old database tables that are simplified like this:
MASTER SLAVE
ident ident
sName sName
sNumber sNumber
sDesc sValue
----- ------
Java Class 'ScenarioMaster' Java Class 'ScenarioSlave'
Each row has a surrogate index across the column ident
, but there is no relationship between MASTER.key
and SLAVE.key
. However, for a table, the MASTER
uniqueness of one sName / sNumber pair is true. So it will be a possible and meaningful composite key (I know it is evil).
In fact, there is a 1: n ratio, meaning that each row MASTER
refers to n rows in the table SLAVE
. Given the description of the column above, the possible population could be
MASTER SLAVE
100 42
'labl' 'labl'
1 1
'some label' 0.1
43
'labl'
1
0.2
Now using hibernate, how could I reflect this relationship in my Java classes? In ScenarioMaster
I declare a Set or List with public getters / setters like
private List<ScenarioSlave> slaves = new ArrayList<ScenarioSlave>();
Sleeping displays for ScenarioMaster
may contain
<bag name="slaves" cascade="all">
<key>
<column name="sName" not-null="true"/>
<column name="sNumber" not-null="true"/>
</key>
<one-to-many class="ScenarioSlave"/>
</bag>
This, however, creates a strage update statement when updating is already persitant ScenarioMaster
using session.saveOrUpdate(scenarioMaster)
.
// create master scn and slave slv
scn.addSlave(slv);
session.saveOrUpdate(scn);
Hibernate:
update
SLAVE
set
sNumber=?,
sName=?,
sValue=?
where
sName=?
and sNumber=?
Hibernate:
update
SLAVE
set
sName=null,
sNumber=null
where
sName=?
and sNumber=?
What am I doing wrong? Where does this second update come from? I think it has something to do with sName / sNumber not being a key for ScenarioSlave
. Why I can't understand.
Note that the sName / sNumber parameters point to valid values ββand that the instance ScenarioMaster
that I want to save through saveOrUpdate
actually has an instance with a non-null ScenarioSlave
in the list slaves
.
EDIT : Composite key is deferred to a separate class using this mapping
<composite-id name="keyId" class="ScenarioKeyId">
<key-property name="name" access="field" column="sName"
type="string" length="20"/>
<key-property name="number" access="field" column="sNumber"
type="long"/>
</composite-id>
I really don't want to create a table NAMENUMBER_KEY
that maps "labl", 1 to something like "key_labl1", which can then be used id
to hibernate. I suppose this is what hibernate does (without using an actual table).
a source to share
Hibernation does not work with composite keys in my experience. This is one of the main problems with Hibernate as far as I've seen. I've worked in the past to avoid using "pure" compound keys; that is, I gave the composite keymaps a unique ID column that Hibernate can then disable.
a source to share
I did a little work (must love Apache Derby ) pretending both tables did not have a composite id. Then I found out that the statement SET ... = null
is most likely issued to invalidate list members slave
.
create table MASTER(
ident numeric(10) not null, -- key column
name char(20) not null,
number numeric(10) not null,
descr char(64) not null
);
create table SLAVE(
ident numeric(10) not null, -- key column
name char(20) not null,
number numeric(10) , -- foreign key f. MASTER.ident
value float not null
);
Here is my test code. I have set up the generator for the main class key as assigned
.
Master master = new Master();
master.setIdent(Integer.valueOf(0));
master.setName("name");
master.setNumber(42);
master.setDescr("name/42 descr");
Slave slv = new Slave("name", 42, 0.001);
master.addSlave(slv);
theSession.beginTransaction();
theSession.saveOrUpdate(master);
theSession.getTransaction().commit();
Then, by allowing the NULL
values ββin the string SLAVE.number
, I get
Hibernate:
update
SLAVE
set
number=null
where
number=?
Hibernate:
update
SLAVE
set
number=?
where
ident=?
Now I only need to figure out how to actually remove the stale rows in slave
and then set the foreign key column to NULL
...
a source to share