2011-09-26 5 views
4

"MailAccount"というクラスと "IncomingServer"と "OutgoingServer"というクラスの間には、2つの1対1の関係があります。Hibernate:1対1の関係による一貫性のないプライマリキーの生成

(これは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{ 
// ... 
} 

、ここ問題来る:

私のアプリケーションがうまく実行されるほとんどの時間、1つの状況があるように思われるが、どの電子メールサーバーが削除されますが、対応するアカウントは対応していません。この呼び出しが行われます。

session.delete(mailAccountInstance); 

休止状態で1対1の関係では、メールアカウントとそのサーバ間の主キーが同じでなければなりませんが、ない場合は、関係が完全に同期しなくなります:

例:

想像を

表 "MailAccount"(現在のAUTO_INCREMENT値:2)

MAIL_ACCOUNT_ID NAME 
0    Account1 
1    Account2 

表 "IncomingMailServer"(現在auto_incremen、テーブルは、このようなデータで満たされていますt値:2)

MAIL_SERVER_ID MAIL_ACCOUNT_ID 
0    0 
1    1 

ここで、ID = 1のアカウントは削除され、新しいアカウントが追加されます。 SOMETIMES次起こる:

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

これは完全に台無し私のデータベースの一貫性。 どうすればこの問題を回避できますか?

+2

解決策がなければ、プライマリキーが等しくなければならないことを1対1の関係で述べる部分は間違っています。リレーションごとに、MAILACCOUNTSに一致するテーブルまたは外部キーを持つ列が存在する必要があります。 – Nicktar

+0

Nicktarは部分的に真です。マッピングの1対1関連は、IncomingMailServerの外部キーMAIL_ACCOUNT_IDの存在によって実現されます。 MailAccountとIncomingMailServerの主キーはまったく異なるかもしれません。あなたの問題の診断は間違っています。一部のメールサーバーが消えた場合は、メールサーバーが削除されたか、アカウントのメールサーバーがnullに設定されているためです。これは、delete-orphan configによってデータベースからメールサーバーが削除されたためです。 –

+0

@Nicktarそれはとても奇妙です。私はそのような一致するテーブルがありません。 "外部キー" MAIL_ACCOUNT_IDはマッチングとは関係ありません。 Incoming-/OutgoingServerの主キーが同期しなくなると、そこからのすべてが完全に台無しになります。キーMAIL_ACCOUNT_IDは依然として正しいMailAccountを参照するかもしれませんが、それは役に立ちません。 HibernateはPKのものにしかマッチしません。 – Timo

答えて

4

共有プライマリキーが必要な場合は、ネイティブIDジェネレータを1回だけ使用できます。最初に独自のIDを生成するメールアカウントを作成しますが、Incoming-またはOutgoingMailServerを作成するときには、これらのIDをmailAccountプロパティから取得する必要があります。それは常にとにかくMAIL_SERVER_IDと同じになりますので、あなたは、MAIL_ACCOUNT_ID列を必要としない

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

は、だから、「外来」発電機を必要としています。

非常に基本的なリファレンスは、bidirectional one-to-one association on a primary keyです。

+0

これは奇妙です。私がそれを行い、 'session.save(mailAccountInstance)'を呼び出すと、ここで 'org.hibernate.tuple.entity.AbstractEntityTuplizer.getPropertyValue(AbstractEntityTuplizer。)でNullPointerExceptionが発生します。java:521) '。私はすでに参照されているメールサーバーかメールアカウントのどちらかがヌルであるかもしれないが、そうではないかどうかを調べた。ここに完全なトレースがあります:http://dl.dropbox.com/u/17844821/zeug/stacktrace.txt – Timo

+0

@greyfairerはほぼ正しいですが、 'column =" MAIL_SERVER_ID "'属性はidタグ内になければなりません。 1対1のタグではない – Fortunato

+0

@Fortunato thx、それを修正しました。 – greyfairer

関連する問題