How to save the correct discriminator value through Hibernate
I am currently trying to map my Java class hierarchy into my database using Hibernate but I keep failing with the following (sub-)classes:
I have a class called MailAccount which has 3 properties (see code below):
public class MailAccount{
long id;
IncomingMailServer incomingServer;
OutgoingMailServer outgoingServer;
public MailAccount(){
super();
}
// Getter and setter omitted
}
The server class hierachy looks like this:
MailServer.java
public abstract class MailServer {
String password;
String host;
String username;
String port;
// Getter and setter omitted
}
IncomingMailServer.java
public abstract class IncomingMailServer extends MailServer {
}
OutgoingMailServer.java
public abstract class OutgoingMailServer extends MailServer {
}
Pop3Server.java
public class Pop3Server extends IncomingMailServer{
public Pop3Server(){
super();
}
}
ImapServer.java
public class ImapServer extends IncomingMailServer{
public ImapServer(){
super();
}
}
SmtpServer.java
public class SmtpServer extends OutgoingMailServer{
public SmtpServer(){
super();
}
}
The properties incomingServer and outgoingServer in MailAccount.java of course only hold instances of either Pop3Server, ImapServer (for incomingServer) or SmtpServer (for outgoingServer).
I use the following mapping configuration:
MailAccount.hbm.xml
<hibernate-mapping package="test.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">
</one-to-one>
<one-to-one name="outgoingServer" cascade="all">
</one-to-one>
</class>
</hibernate-mapping>
MailServer.hbm.xml
<hibernate-mapping>
<class name="test.server.MailServer" table="MAILSERVER" abstract="true">
<id name="id" type="long" access="field">
<column name="MAIL_SERVER_ID" />
<generator class="native" />
</id>
<discriminator column="SERVER_TYPE" type="string"/>
<property name="password" column="PASSWORD" />
<property name="host" column="HOST" />
<property name="username" column="USERNAME" />
<property name="port" column="PORT" />
<one-to-one name="mailAccount" class="test.account.MailAccount" foreign-key="MAIL_SERVER_ID"></one-to-one>
<subclass name="test.server.incoming.ImapServer" extends="test.server.incoming.IncomingMailServer" discriminator-value="IMAP_SERVER">
</subclass>
<subclass name="test.server.incoming.Pop3Server" extends="test.server.incoming.IncomingMailServer" discriminator-value="POP3_SERVER">
</subclass>
<subclass name="test.server.outgoing.SmtpServer" extends="test.server.outgoing.OutgoingMailServer" discriminator-value="SMTP_SERVER">
</subclass>
<subclass name="test.server.incoming.IncomingMailServer" extends="test.server.MailServer" abstract="true" discriminator-value="INCOMING_SERVER">
</subclass>
<subclass name="test.server.outgoing.OutgoingMailServer" extends="test.server.MailServer" abstract="true" discriminator-value="OUTGOING_SERVER">
</subclass>
</class>
</hibernate-mapping>
The problem: Whenever I tell Hibernate to save an instance of MailAccount, like this:
session = getSession();
transaction = session.beginTransaction();
session.save(mailAccount);
transaction.commit();
.. Hibernate stores everything correctly EXCEPT for the discriminator column SERVER_TYPE in the table MailServer. In this column, Hibernate should store either "IMAP_SERVER", "POP3_SERVER" or "SMTP_SERVER" but instead it saves either "INCOMING_SERVER" or "OUTGOING_SERVER".
When I try to load this entity from the database, an exception occurs (of course) because Hibernate is trying to instantiate objects of type "IncomingMailServer" or "OutgoingMailServer" which are both abstract. So, how do I get Hibernate to save the correct type?
Example: If the property incomingServer holds an instance of Pop3Server, then Hiberante should store that into my database and when I load the according开发者_如何学JAVA MailAccount back, I want Hibernate to recreate an instance of Pop3Server.
Note: I am pretty new to Hibernate and these are my first steps with it, so please be gentle :-) . I am aware that my .hmb.xml files might look messy, so if you have suggestions for improvements, go ahead :-)
Nesting of <subclass>
elements should resemble the inheritance hierarchy:
<subclass name="test.server.incoming.IncomingMailServer" extends="test.server.MailServer" abstract="true" discriminator-value="INCOMING_SERVER">
<subclass name="test.server.incoming.ImapServer" extends="test.server.incoming.IncomingMailServer" discriminator-value="IMAP_SERVER">
</subclass>
<subclass name="test.server.incoming.Pop3Server" extends="test.server.incoming.IncomingMailServer" discriminator-value="POP3_SERVER">
</subclass>
</subclass>
<subclass name="test.server.outgoing.OutgoingMailServer" extends="test.server.MailServer" abstract="true" discriminator-value="OUTGOING_SERVER">
<subclass name="test.server.outgoing.SmtpServer" extends="test.server.outgoing.OutgoingMailServer" discriminator-value="SMTP_SERVER">
</subclass>
</subclass>
精彩评论