Однонаправленный Hibernate один-ко-многим в существующей БД - PullRequest
2 голосов
/ 03 февраля 2009

Привет, эксперты по переполнению стека, мне нужен ваш опыт:

Я пытаюсь использовать Hibernate на существующей базе данных. В настоящее время я пытаюсь загрузить объект User и список объектов UserData, которые идут вместе.

в БД (упрощенная) компоновка

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

Таким образом, каждый объект User соответствует всем объектам UserData, где UserData.parentuid = User.uid.

Файл сопоставления классов My User

    <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

    <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 выдает ошибку «Repeated column in mapping».
  • В настоящее время в поле uid все еще есть «Повторяющийся столбец в отображении», я использую для <list-index />
  • Я не понимаю, где я указываю, что UserData.parentuid является внешним ключом и что список должен использовать User.uid в качестве ключа.

Надеюсь, кто-то сможет помочь.


Когда вы определяете и «один ко многим», и «многие к одному», разве это не делает его двунаправленным? Текущая рабочая модель является однонаправленной, а UserData не имеет ссылки на пользователя. Ваше предложение не выполнено, поскольку Hibernate не смог найти метод get или set для User в UserData.

Подразумевается ли, что этот код использует 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 ]

0 голосов
/ 04 мая 2009

->

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

Попробуйте, я просто изменил ключевую колонку в качестве parentuid на uid. (И лучше использовать набор в отображениях hibernate)

ура, Нагендра Прасад ..

0 голосов
/ 06 февраля 2009

Я думаю, что вы близки, но List, вероятно, не та структура данных, которую вы хотите в своем новом классе User. Список подразумевает упорядочение дочерних элементов, которого нет в таблицах. Если у вас есть индексированная коллекция, такая как список, у данных должен быть отдельный столбец, который предоставляет индекс, поэтому возникает проблема «повторяющийся столбец в отображении».

Эмпирические правила, которые я использую, таковы: каждое отображение должно включать запись для каждого члена класса, который он отображает. Так, например, ваш класс User должен иметь запись для своей коллекции FieldData, но вашему отображению FieldData не требуется запись для parentuid, поскольку этот столбец не отображается на элемент класса FieldData - он просто используется для помещения FieldData внутри коллекции в родительском объекте.

Если объект User действительно содержит упорядоченную коллекцию FieldData, вместо этого используйте набор. С другой стороны, я думаю, что вы, скорее всего, захотите использовать карту FieldData, используя имя поля в качестве индекса. Тогда класс FieldData не должен отображать столбец 'field' и не будет иметь его в качестве члена, он просто будет иметь значение (и любые другие поля из этой таблицы - конечно, если в действительности есть только один столбец) Если оставить карту, вы можете просто получить карту строк и строк.

0 голосов
/ 18 февраля 2009

Это последняя разработка по этой проблеме. Эту конфигурацию можно успешно загрузить из базы данных. Сохранение не работает. Вместо этого я решил изменить дизайн базы данных, поэтому я публикую это здесь для справки для других, прежде чем отказаться от этого подхода.

    <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>
0 голосов
/ 03 февраля 2009

Попробуйте это (сухой код):

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

Если это работает, попробуйте добавить индекс и каскад, которые я пропустил.

ура
Митч

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...