一对多映射//如何映射遗留表的关联(Hibernate)
我有两个旧式数据库表,以简化的方式排列如下:一对多映射//如何映射遗留表的关联(Hibernate),hibernate,database-design,orm,Hibernate,Database Design,Orm,我有两个旧式数据库表,以简化的方式排列如下: MASTER SLAVE ident ident sName sName sNumber sNumber sDesc sValue ----- ------ Java Cl
MASTER SLAVE
ident ident
sName sName
sNumber sNumber
sDesc sValue
----- ------
Java Class 'ScenarioMaster' Java Class 'ScenarioSlave'
每行通过ident
列有一个代理索引,但是MASTER.key
和SLAVE.key
之间没有关系。但是,对于MASTER
表,一个sName/sNumber对的唯一性是正确的。因此,这将是一个可能且有意义的复合键(我确实知道那些是邪恶的)
事实上,存在一个1:n关系,这意味着主行引用从表中的n行。根据上面的列描述,可能的人口可能是
MASTER SLAVE
100 42
'labl' 'labl'
1 1
'some label' 0.1
43
'labl'
1
0.2
现在,使用hibernate,如何在java类中反映这种关系?在ScenarioMaster
中,我将声明一个集合或列表,其中包含公共getter/setter,如
private List<ScenarioSlave> slaves = new ArrayList<ScenarioSlave>();
但是,当使用session.saveOrUpdate(ScenarioMaster)
更新已经存在的ScenarioMaster
实体时,这会创建一个strage update语句
我做错了什么?第二次更新来自哪里?
我想这与sName/sNumber不是ScenarioSlave
的键有关。我不太明白,为什么
请注意,sName/sNumber参数确实指向有效值,并且我希望通过saveOrUpdate
持久化的ScenarioMaster
实例实际上在slaves
列表中有一个非空的ScenarioSlave
实例
编辑:使用此映射将复合键延迟到单独的类
<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>
我真的不想创建一个表NAMENUMBER\u KEY
,它将'labl',1映射到类似'KEY\u labl1'的东西,然后可以用作hibernate的id
。我想,这就是hibernate所做的(不使用实际的表)。根据我的经验,hibernate不能很好地使用复合键。就我所见,这是Hibernate的一个主要问题。过去,我一直通过避免使用“纯”复合键来解决这个问题;也就是说,我给复合键表提供了一个唯一的ID列,Hibernate可以使用它。我试了一下(不得不爱),假装两个表都没有复合ID。
然后我发现,设置…=发出null
语句很可能是为了使从属
列表的成员无效
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
);
这是我的测试代码。我将主类密钥的生成器设置为分配的
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();
然后,允许SLAVE.number
行中的NULL
值,我得到
Hibernate:
update
SLAVE
set
number=null
where
number=?
Hibernate:
update
SLAVE
set
number=?
where
ident=?
现在我只需要弄清楚如何实际删除SLAVE
中的过时行,而不是将外键列设置为NULL
。让我们两人(关于引入唯一Id列)很高兴知道我不是唯一使用该解决方案的人。从DB设计的角度来看,不得不这样做有点令人沮丧,但它确实很好地解决了问题。您能详细介绍一下这种方法吗?当说“给定复合键表一个唯一的ID列”时,您是否更改了表?恐怕我不能这样做,但我也怀疑您是否这样做了。在初始开发期间的测试显示了Hibernate和复合键的问题,因此我们更改了表的初始规范,为该表包含一个单独的主键列。
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();
Hibernate:
update
SLAVE
set
number=null
where
number=?
Hibernate:
update
SLAVE
set
number=?
where
ident=?