一对多映射//如何映射遗留表的关联(Hibernate)

时间:2009-05-11 17:00:12

标签: hibernate database-design orm

我有两个遗留数据库表,以简化的方式布局:

MASTER                        SLAVE
ident                         ident
sName                         sName
sNumber                       sNumber
sDesc                         sValue
-----                         ------
Java Class 'ScenarioMaster'   Java Class 'ScenarioSlave'

每一行都有ident列的代理索引,但MASTER.keySLAVE.key之间没有任何关系。但是,对于MASTER表,一个sName / sNumber对的唯一性为true。因此,这将是一个可能且有意义的复合键(我知道那些是邪恶的)。

实际上,有一个1:n关系意味着MASTER表中每个SLAVE行引用 n 行。鉴于上面的列描述,可能的人口可能是

MASTER                        SLAVE
100                           42
'labl'                        'labl'
1                             1
'some label'                  0.1
                              43
                             'labl'
                              1
                              0.2

现在,使用hibernate,我怎么能在我的java类中反映这种关系?在ScenarioMaster中,我将使用公共getter / setter声明一个Set或List,如

private List<ScenarioSlave> slaves = new ArrayList<ScenarioSlave>();

ScenarioMaster的hibernate-mappings可以包含

<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>

但是,在使用ScenarioMaster更新已经持久的session.saveOrUpdate(scenarioMaster)实体时,这会创建一个strage更新语句。

// 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=?   

我做错了什么?第二次更新来自哪里? 我想这与sName / sNumber不是ScenarioSlave的关键有关。我无法弄明白,为什么。

请注意,sName / sNumber参数确实指向有效值,并且我想通过ScenarioMaster保留的saveOrUpdate实例实际上在{{ScenarioSlave实例中有一个非空slaves实例1}}列表。

编辑:使用此映射将复合键推迟到单独的类

<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_KEY,它将'labl',1 映射到类似'key_labl1'的表格,然后可以使用作为hibernate的id。我想,这就是hibernate的作用(不使用实际的表)。

2 个答案:

答案 0 :(得分:2)

根据我的经验,

Hibernate对复合键不起作用。就我所见,这是Hibernate的一个主要问题。我过去曾经通过避免使用“纯粹”的复合键来解决它;也就是说,我给复合键表一个唯一的ID列,然后Hibernate可以使用它。

答案 1 :(得分:0)

我尝试了一下(得到爱Apache Derby)假装,两个表都没有复合ID。 然后我发现,最有可能发出SET ... = null语句以使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
);

这是我的测试代码。我将主类密钥的生成器设置为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();

然后,在NULL行中允许SLAVE.number值,我得到

Hibernate: 
    update
        SLAVE 
    set
        number=null 
    where
        number=?
Hibernate: 
    update
        SLAVE 
    set
        number=? 
    where
        ident=?

现在我只需弄清楚如何在SLAVE中实际删除陈旧行,而不是将外键列设置为NULL ......