2

您好 Stack Overflow 专家,我需要您的专业知识:

我正在尝试在现有数据库上使用 Hibernate。目前我正在尝试加载一个用户对象和一个用户数据对象列表。

在数据库中(简化的)布局是

|    User      |      |          UserData               |
----------------      -----------------------------------
uid | username |      | uid | parentuid | field | value | 

因此,每个 User 对象都匹配 UserData.parentuid = User.uid 的所有 UserData 对象。

我的用户类映射文件

    <class name="com.agetor.commons.security.User" table="ac_users">
    <id name="uid" column="uid" type="long" >
        <!--<generator class="native"/>-->
    </id>
    <property name="username" column="username" />   

    <list name="fieldData" cascade="all">
        <key column="parentuid" not-null="true" />
        <index column="parentuid" />
        <one-to-many class="com.agetor.commons.fields.FieldData"/>
    </list>

</class> 

Mu UserData 映射文件

    <class name="com.agetor.commons.fields.FieldData" table="ac_userdef_data">
    <id name="uid" column="uid" type="long" >
    <!--<generator class="native"/> -->
    </id>
    <!--<property name="parentuid" column="parentuid" />   -->
    <property name="fieldname" column="fieldname" />
    <property name="value" column="value" />
</class>

到目前为止,我已经尝试了许多不同的配置,并且所有配置都有不同程度的失败。此处粘贴的代码不起作用。

  • parentuid 属性被注释掉,否则 Hibernate 会给出“映射中的重复列”错误。
  • 目前在uid字段上仍然有一个“映射中的重复列”,我用于<list-index />
  • 我不明白我在哪里指定 UserData.parentuid 是外键并且列表应该使用 User.uid 作为键。

我希望有人能够提供帮助。


当您同时定义一对多和多对一时,这不是使其成为双向吗?当前的工作模型是单向的,并且 UserData 没有对 User 的引用。您的建议失败,因为 Hibernate 在 UserData 上找不到用户的 get 或 set 方法。

是否暗示此代码使用 User.uid 作为键并将其与 UserData.parentuid 列匹配?还是在其他地方指定了这个事实?

  <list name="fieldData" inverse="true">
    <key column="parentuid" not-null="true" />
    <one-to-many class="com.agetor.commons.fields.FieldData"/>
  </list>

我仍在学习 Hibernate,并通过我能找到的文档和示例进行工作。

4

4 回答 4

0

试试这个(干代码):

<class name="com.agetor.commons.security.User" table="ac_users">
  <id name="uid" column="uid" type="long" >
    <!--<generator class="native"/>-->
  </id>
  <property name="username" column="username" />   

  <list name="fieldData" inverse="true">
    <key column="parentuid" not-null="true" />
    <one-to-many class="com.agetor.commons.fields.FieldData"/>
  </list>
</class>

<class name="com.agetor.commons.fields.FieldData" table="ac_userdef_data">
  <id name="uid" column="uid" type="long" >
    <!--<generator class="native"/> -->
  </id>
  <many-to-one name="user" class="com.agetor.commons.security.User" fetch="join">
     <column name="parentuid" not-null="true"/>
  </many-to-one>
  <property name="fieldname" column="fieldname" />
  <property name="value" column="value" />
</class>

如果可行,请尝试添加我遗漏的索引和级联内容。

干杯,
米奇

于 2009-02-03T15:51:27.960 回答
0

我认为您很接近,但 List 可能不是您在新 User 类中想要的数据结构。列表意味着子元素的排序,而表似乎没有。如果您有一个像列表这样的索引集合,则数据必须有一个单独的列来提供索引,因此会出现“映射中的重复列”问题。

我使用的经验法则是 - 每个映射都应该包含它所映射的类的每个成员的条目。因此,例如,您的 User 类应该为其 FieldData 集合提供一个条目,但您的 FieldData 映射不需要 parentuid 的条目,因为该列不映射到 FieldData 类的元素 - 它只是用来放置 FieldData在父对象的集合中。

如果 User 对象确实包含一个有序的 FieldData 集合,则使用一个集合来代替。另一方面,我认为您更可能需要 FieldData 的地图,使用“字段”名称作为索引。然后 FieldData 类不需要映射“字段”列并且不会将其作为成员,它只会具有值(以及该表中的任何其他字段 - 当然如果真的只有一列留给映射,您可能最终会得到一个字符串到字符串的映射。

于 2009-02-06T00:48:20.197 回答
0

这是这个问题的最新进展。此配置可以成功从数据库加载。保存不起作用。我决定改为更改数据库设计,因此在我放弃这种方法之前,我将其发布在这里以供其他人参考。

    <class name="com.agetor.commons.security.User" table="ac_users">
    <id name="uid" column="uid" type="long" >
        <generator class="increment"/>
    </id>
    <property name="deleted" column="deleted" />
    <property name="username" column="username" />   
    <property name="password" column="passwd" />
    <property name="disabled" column="disabled" />
    <property name="lockout" column="lockout" />
    <property name="expires" column="expires" />
    <bag name="fieldData" lazy="extra">
        <key column="parentuid" not-null="true" />
        <one-to-many class="com.agetor.commons.fields.FieldData"/>
    </bag>
    <bag name="groups" table="ac_group_rel" access="field" lazy="extra">
        <key column="useruid"/>         
        <many-to-many column="groupuid" class="com.agetor.commons.security.Group"/>
    </bag>         
    <join table="ac_userdef_data" optional="true" fetch="join">
        <subselect>
            select
                *
            from
                ac_userdef_data data
            where
                data.objectname = 'user' and
                data.fieldname = 'firstname'
        </subselect>
        <key column="parentuid" />
        <property name="firstname" formula="(select data.value from ac_userdef_data data where data.fieldname = 'firstname' and data.uid = uid)"/>
    </join>
    <join table="ac_userdef_data" optional="true" fetch="join">
        <subselect>
            select
                *
            from
                ac_userdef_data data
            where
                data.objectname = 'user' and
                data.fieldname = 'lastname'
        </subselect>        
        <key column="parentuid" />
        <property name="lastname" formula="(select data.value from ac_userdef_data data where data.fieldname = 'lastname' and data.uid = uid)"/>
    </join>

</class>
于 2009-02-18T08:02:52.377 回答
0

-->

<list name="fieldData" cascade="all">
    <key column="uid" not-null="true" />
    <index column="parentuid" />
    <one-to-many class="com.agetor.commons.fields.FieldData"/>
</list>

试试这个,我只是将 key coloumn 作为 parentuid 更改为 uid。(并且在休眠映射中更好地使用 set)

干杯,纳根德拉普拉萨德..

于 2009-05-04T06:34:35.647 回答