Hibernate: непоследовательная генерация первичного ключа из-за отношения один к одному - PullRequest
4 голосов
/ 26 сентября 2011

У меня здесь два взаимно-однозначных отношения между классом с именем «MailAccount» и классами «IncomingServer» и «OutgoingServer».

(Это Java-приложение, работающее на серверах Tomcat и Ubuntu).

Отображение выглядит так:

MailAccount.hbm.xml

<hibernate-mapping package="com.mail.account">
    <class name="MailAccount" table="MAILACCOUNTS" dynamic-update="true">

        <id name="id" column="MAIL_ACCOUNT_ID">
            <generator class="native" />
        </id>

        <one-to-one name="incomingServer" cascade="all-delete-orphan">
        </one-to-one>
        <one-to-one name="outgoingServer" cascade="all-delete-orphan">
        </one-to-one>

    </class>
</hibernate-mapping>

IncomingMailServer.hbm.xml

<hibernate-mapping>
    <class name="com.IncomingMailServer" table="MAILSERVER_INCOMING" abstract="true">

        <id name="id" type="long" access="field">
            <column name="MAIL_SERVER_ID" />
            <generator class="native" />
        </id>

        <discriminator column="SERVER_TYPE" type="string"/>

        <many-to-one name="mailAccount" column="MAIL_ACCOUNT_ID" not-null="true" unique="true" />

        <subclass name="com.ImapServer" extends="com.IncomingMailServer" discriminator-value="IMAP_SERVER" />           
        <subclass name="com.Pop3Server" extends="com.IncomingMailServer" discriminator-value="POP3_SERVER" />

    </class>
</hibernate-mapping>

OutgoingMailServer.hbm.xml

<hibernate-mapping>
    <class name="com.OutgoingMailServer" table="MAILSERVER_OUTGOING" abstract="true">

        <id name="id" type="long" access="field">
            <column name="MAIL_SERVER_ID" />
            <generator class="native" />
        </id>

        <discriminator column="SERVER_TYPE" type="string"/>

        <many-to-one name="mailAccount" column="MAIL_ACCOUNT_ID" not-null="true" unique="true" />

        <subclass name="com.SmtpServer" extends="com.OutgoingMailServer" discriminator-value="SMTP_SERVER" />

    </class>
</hibernate-mapping>

Иерархия классов выглядит следующим образом:

public class MailAccount{
 IncomingMailServer incomingServer;
 OutgoingMailServer outgoingServer;
}

public class MailServer{
 HostAddress hostAddress;
 Port port;
}

public class IncomingMailServer extends MailServer{
 // ...
}

public class OutgoingMailServer extends MailServer{
 // ...
}

public class ImapServer extends IncomingMailServer{
 // ...
}

public class Pop3Server extends IncomingMailServer{
 // ...
}

public class SmtpServer extends OutgoingMailServer{
 // ...
}

Теперь, вот проблема :

Хотя в большинстве случаев мое приложение работает нормально, кажется, что существует одна ситуация, когда почтовые серверы удаляются, но соответствующая учетная запись не удаляется, и именно тогда этот вызов выполняется:

session.delete(mailAccountInstance);

В отношении «один-к-одному» в Hibernate первичные ключи между почтовой учетной записью и ее серверами должны быть равны, в противном случае отношение полностью теряет синхронизацию:

Пример:

Представьте себе, таблицы заполнены такими данными:

Таблица «MailAccount» (текущее значение auto_increment: 2)

MAIL_ACCOUNT_ID NAME
0               Account1
1               Account2

Таблица "IncomingMailServer" (текущее значение auto_increment: 2)

MAIL_SERVER_ID  MAIL_ACCOUNT_ID
0               0
1               1

Теперь изображение с идентификатором = 1 удаляется и добавляются новые учетные записи. Затем происходит ИНОГДА:

Таблица «MailAccount» (текущее значение auto_increment: 3)

MAIL_ACCOUNT_ID NAME
0               Account1
1               Account2
2               Account3

Таблица "IncomingMailServer" (текущее значение auto_increment: 2)

MAIL_SERVER_ID  MAIL_ACCOUNT_ID
0               0
1               2

Это полностью нарушает целостность моей базы данных. Как я могу избежать этого?

1 Ответ

4 голосов
/ 05 января 2012

Если вам нужен общий первичный ключ, вы можете использовать собственный генератор идентификаторов только один раз. Сначала вы создаете почтовую учетную запись, которая будет генерировать свой собственный идентификатор, но когда вы создаете Incoming- или OutgoingMailServer, они должны получить свой идентификатор из свойства mailAccount.

Итак, вам нужен «чужой» генератор:

<class name="OutgoingMailServer">
    <id name="id" column="MAIL_SERVER_ID"> 
       <generator class="foreign"> 
           <param name="property">mailAccount</param> 
       </generator>
    </id>
    <one-to-one name="mailAccount" not-null="true" constrained="true"/>
<class>

Вам не нужен столбец MAIL_ACCOUNT_ID, так как он всегда будет идентичен MAIL_SERVER_ID.

Довольно просто следуйте указаниям о двунаправленной связи один-к-одному на первичном ключе .

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