代码之家  ›  专栏  ›  技术社区  ›  mats

一对多映射//如何映射旧表的关联(休眠)

  •  1
  • mats  · 技术社区  · 16 年前

    我有两个传统数据库表,按如下简化方式布局:

    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 中的行 SLAVE 表。考虑到上面的列描述,可能的填充可以是

    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>();
    

    的休眠映射 情景演说家 可以包含

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

    但是,当更新已经存在的监视对象时,这将创建一个strage update语句。 情景演说家 实体使用 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=?   
    

    我做错什么了?第二次更新是从哪里来的? 我想这与sname/snumber不是 ScenarioSlave . 我不太明白为什么。

    请注意,sname/snumber参数确实指向有效值,并且 情景演说家 实例我想通过 saveOrUpdate 实际上有一个非空值 情景喜剧 实例中 slaves 名单。

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

    <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 哪些地图 “拉伯”,1 像这样的 “KY-LabLL1” 然后可以用作 id 用于休眠。我想,这就是Hibernate所做的(不使用实际的表)。

    2 回复  |  直到 16 年前
        1
  •  2
  •   Paul Sonier    16 年前

    根据我的经验,Hibernate不能很好地使用复合键。据我所见,这是冬眠的一个主要问题。在过去,我通过避免使用“纯”复合键来解决这个问题;也就是说,我为复合键表提供了一个惟一的ID列,然后Hibernate就可以解决这个问题。

        2
  •  0
  •   mats    16 年前

    我尝试了一点(要爱 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 而不是将外键列设置为 无效的