отображение нескольких наборов в одной таблице в спящем режиме

У меня есть класс User и Log (который я не могу изменить):

class User {
    private long id;
    private String name;
    private Set<Log> accessLogs;
    private Set<Log> actionLogs;
}

class Log {
    private String what;
    private Date when;
}

Возможное отображение будет выглядеть так:

<class name="com.example.User" table="users">
    <id name="id" access="field">
        <generator class="native" />
    </id>

    <property name="name" length="256" />

    <set name="accessLogs" table="user_access_logs" cascade="all-delete-orphan" order-by="`when`">
        <key column="user_id" />
        <composite-element class="com.example.Log">
            <property name="what" length="512" />
            <property name="when" column="`when`" />
        </composite-element>
    </set>

    <set name="actionLogs" table="user_action_logs" cascade="all-delete-orphan" order-by="`when`">
        <key column="user_id" />
        <composite-element class="com.example.Log">
            <property name="what" length="512" />
            <property name="when" column="`when`" />
        </composite-element>
    </set>

</class>

Это отлично работает и сопоставляется со следующими таблицами базы данных:

users
+----+------+
| id | name |
+----+------+
|  1 | john |
|  2 | bill |
|  3 | nick |
+----+------+

user_access_logs
+---------+------------+---------------------+
| user_id | what       | when                |
+---------+------------+---------------------+
|       1 | logged in  | 2010-09-21 11:25:03 |
|       1 | logged out | 2010-09-21 11:38:24 |
|       1 | logged in  | 2010-09-22 10:19:39 |
|       2 | logged in  | 2010-09-22 11:03:18 |
|       1 | logged out | 2010-09-22 11:48:16 |
|       2 | logged in  | 2010-09-26 12:45:18 |
+---------+------------+---------------------+

user_action_logs
+---------+---------------+---------------------+
| user_id | what          | when                |
+---------+---------------+---------------------+
|       1 | edit profile  | 2010-09-21 11:28:13 |
|       1 | post comment  | 2010-09-21 11:30:40 |
|       1 | edit profile  | 2010-09-21 11:31:17 |
|       1 | submit link   | 2010-09-22 10:21:02 |
|       2 | submit review | 2010-09-22 11:10:22 |
|       2 | submit link   | 2010-09-22 11:11:39 |
+---------+---------------+---------------------+

Мой вопрос заключается в том, как в спящем режиме можно сопоставить эти 2 набора (accessLogs и actionLogs) в одну и ту же таблицу, создав следующую схему для журналов:

user_logs
+---------+---------------+---------------------+--------+
| user_id | what          | when                | type   |
+---------+---------------+---------------------+--------+
|       1 | logged in     | 2010-09-21 11:25:03 | access |
|       1 | edit profile  | 2010-09-21 11:28:13 | action |
|       1 | post comment  | 2010-09-21 11:30:40 | action |
|       1 | edit profile  | 2010-09-21 11:31:17 | action |
|       1 | logged out    | 2010-09-21 11:38:24 | access |
|       1 | logged in     | 2010-09-22 10:19:39 | access |
|       1 | submit link   | 2010-09-22 10:21:02 | action |
|       2 | logged in     | 2010-09-22 11:03:18 | access |
|       2 | submit review | 2010-09-22 11:10:22 | action |
|       2 | submit link   | 2010-09-22 11:11:39 | action |
|       1 | logged out    | 2010-09-22 11:48:16 | access |
|       2 | logged in     | 2010-09-26 12:45:18 | access |
+---------+---------------+---------------------+--------+

Изменить: я хочу сохранить код Java и семантику Set как есть. Я ищу что-то вроде дискриминатора, формулы или расширения API гибернации, которое решит эту проблему, не касаясь кода Java. Может быть, что-то в этом роде (следует воображаемая конфигурация гибернации):

<set name="accessLogs" table="user_logs" ... formula="type='access'">
    <key column="user_id" />
    <composite-element class="Log">
        ...
    </composite-element>
</set>

<set name="actionLogs" table="user_logs" ... formula="type='action'">
    <key column="user_id" />
    <composite-element class="Log">
        ...
    </composite-element>
</set>

Edit2: у меня еще нет полного решения этой проблемы. Я уверен, что это можно сделать, возможно, расширив какой-нибудь спящий API.


person cherouvim    schedule 05.11.2010    source источник


Ответы (3)


Как писал Маурицио, вам нужно использовать атрибут where для извлечения только тех строк, которые принадлежат каждой коллекции.

Чтобы вставить строки с помощью дополнительного столбца, вам нужно добавить следующий элемент внутрь <set>:

<sql-insert>
  insert into user_logs(user_id, what, [when], type)
  values(?, ?, ?, 'access')
</sql-insert>

По сути, это говорит Hibernate использовать этот конкретный SQL вместо его генерации. Обратите внимание, что мне пришлось вручную экранировать столбец when.

Бонус: чтобы добавить дополнительный столбец в БД, используйте следующее (после закрытия <class>)

<database-object>
  <create>alter table user_logs add type char(6)</create>
  <drop></drop>
</database-object>

Интересный момент: я написал и протестировал это с помощью NHibernate, но он был портирован напрямую, поэтому он должен работать точно так же.

person Diego Mijelshon    schedule 14.11.2010

Вы пытались установить карту таким образом:

<set name="accessLogs" table="user_logs" where="type='access'">    
person Maurizio Cucchiara    schedule 05.11.2010
comment
Спасибо, это круто. Теперь мне нужно только найти способ внедрить доступ в столбец типа, которого нет в моей модели. - person cherouvim; 05.11.2010
comment
+1 Это то, что я сделал в похожей ситуации, и это работает нормально. - person oksayt; 08.11.2010
comment
Да, но я не могу различить журналы доступа и журналы действий, поскольку в таблице user_logs есть только user_id, what, when. - person cherouvim; 08.11.2010
comment
Мне нужно сделать это через конфигурацию гибернации. Я не могу изменить или расширить свою модель. - person cherouvim; 08.11.2010
comment
тогда есть единственный способ сделать эту цепочку, где условие: где=что = 'вошел в систему' или что='что еще' - person Maurizio Cucchiara; 08.11.2010

почему не получается просто объединить списки в один список? Оба ваших списка относятся к одному классу.

РЕДАКТИРОВАТЬ. Если вы хотите сохранить 2 списка, создайте третий список, который представляет собой комбинацию, и сохраните только его. Вам нужно будет контролировать доступ к аксессорам двух списков, чтобы вы знали, когда обновить третий, но это не должно быть слишком сложно.

person hvgotcodes    schedule 05.11.2010
comment
Я хотел бы решить эту проблему, только изменив код сопоставления спящего режима. - person cherouvim; 05.11.2010
comment
@cherouvim, если у вас есть 2 набора, вам нужно сопоставить наборы. Если вы хотите один набор, вы должны изменить свой код. - person hvgotcodes; 05.11.2010
comment
Мне нужно 2 набора, и я могу их сопоставить, но я хочу, чтобы они были сопоставлены с одной таблицей. - person cherouvim; 05.11.2010
comment
@cherouvim, затем попробуйте создать третий набор, как я предложил в своем ответе, и сопоставьте его - тогда у вас есть один постоянный набор, и логика вашего домена работает с двумя наборами... - person hvgotcodes; 05.11.2010
comment
Третий набор выполнит эту работу, но мне нужно знать, можно ли это решить только с помощью конфигурации или расширений гибернации. - person cherouvim; 05.11.2010