【问题标题】:one-to-many mapping // how to map an association of legacy tables (Hibernate)一对多映射//如何映射遗留表的关联(Hibernate)
【发布时间】:2009-05-11 17:00:11
【问题描述】:

我有两个旧数据库表,以这样的简化方式布局:

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

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

实际上,存在 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 的休眠映射可能包含

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

但是,这会在使用 session.saveOrUpdate(scenarioMaster) 更新已持久的 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=?   

我做错了什么?第二次更新来自哪里? 我想这与 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_KEY'labl', 1 映射到类似 'key_labl1' 的东西,然后可以用作@ 987654343@ 用于休眠。我想,这就是 hibernate 所做的(不使用实际的表)。

【问题讨论】:

    标签: hibernate database-design orm


    【解决方案1】:

    根据我的经验,Hibernate 不适用于复合键。就我所见,这是 Hibernate 的一个主要问题。过去我通过避免使用“纯”复合键来解决它;也就是说,我为复合键表提供了一个唯一的 ID 列,Hibernate 可以使用它。

    【讨论】:

    • 让我们两个人(关于引入唯一 ID 列)
    • 很高兴知道我不是唯一使用/使用该解决方案的人。从数据库设计的角度来看,这有点令人沮丧,但它确实很好地解决了问题。
    • 您能详细说明一下这种方法吗?当您说“给定复合键表一个唯一的 ID 列”时,您是否 ALTER TABLE 您的表?恐怕我做不到,但我也怀疑这就是你所做的。
    • 初始开发期间的测试表明 Hibernate 和复合键存在问题,因此我们更改了表的初始规范,为该表包含一个单独的主键列。
    【解决方案2】:

    我试了一下(一定很喜欢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();
    

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多