Hibernate:由于一对一关系而导致主键生成不一致

时间:2011-09-26 11:41:47

标签: java hibernate

我在名为“MailAccount”的类与“IncomingServer”和“OutgoingServer”类之间有两个一对一的关系。

(这是在Tomcat和Ubuntu服务器版上运行的Java应用程序)。

映射如下所示:

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

现在,ID = 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 个答案:

答案 0 :(得分:4)

如果需要共享主键,则只能使用本机ID生成器一次。您首先创建邮件帐户,这将生成自己的ID,但是当您创建Incoming-或OutgoingMailServer时,这些需要从mailAccount属性中获取其ID。

所以你需要&#34;外国&#34;发生器:

<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完全相同。

基本遵循关于bidirectional one-to-one association on a primary key的参考资料。