我有以下类层次结构:
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{
// ...
}
我的(简化的)映射文件如下所示:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<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>
<component name="incomingServer">
<component name="hostAddress">
<property name="address" column="IS_HOST_ADDRESS"></property>
</component>
<component name="port">
<property name="portNumber" column="IS_PORT_NUMBER"></property>
</component>
</component>
<component name="outgoingServer">
<component name="hostAddress">
<property name="address" column="OS_HOST_ADDRESS"></property>
</component>
<component name="port">
<property name="portNumber" column="OS_PORT_NUMBER"></property>
</component>
</component>
</class>
</hibernate-mapping>
问题:当我调用 session.save(mailAccountInstance);
时,Hibernate 抛出此异常:
org.hibernate.InstantiationException: Cannot instantiate abstract class or interface: IncomingMailServer
因此,我将以下几行添加到传入服务器组件中:
<discriminator column="SERVER_TYPE" type="string"/>
<subclass name="ImapServer" extends="IncomingMailServer" discriminator-value="IMAP_SERVER" />
<subclass name="Pop3Server" extends="IncomingMailServer" discriminator-value="POP3_SERVER" />
以及发送服务器:
<discriminator column="SERVER_TYPE" type="string"/>
<subclass name="SmtpServer" extends="OutgoingMailServer" discriminator-value="SMTP_SERVER" />
但是现在,Hibernate 给了我这个错误消息:
org.xml.sax.SAXParseException: The content of element type "component" must match "(meta*,tuplizer*,parent?,(property|many-to-one|one-to-one|component|dynamic-component|any|map|set|list|bag|array|primitive-array)*)".
显然,Hibernate 不喜欢组件中的这些标签。
我该如何解决这个问题?
Ps:我已经尝试将 IncomingServer 和 OutgoingServer 分别移动到它们自己的表中,并通过一对一映射它们。这可行,但会导致数据库不一致,因为我注意到 MailAccount 和 IncomingServer/OutgoingServer 必须始终具有相同的主键 id。如果不是,一切都会不同步,并且主键的自动增量值不再匹配(Mailaccount 和服务器之间)。
最佳答案
这个映射对我有用:
hibernate 映射
<class name="MailServer" abstract="true" table="SERVER">
<id name="id" column="id">
<generator class="native" />
</id>
<discriminator column="SERVER_TYPE" type="string"/>
<subclass name="IncomingMailServer" abstract="true">
<property name="address" column="IS_HOST_ADDRESS"></property>
<property name="portNumber" column="IS_PORT_NUMBER"></property>
</subclass>
<subclass name="OutgoingMailServer" abstract="true">
<property name="address" column="OS_HOST_ADDRESS"></property>
<property name="portNumber" column="OS_PORT_NUMBER"></property>
</subclass>
</class>
<subclass name="IMAPServer" extends="com.mail.account.IncomingMailServer"
discriminator-value="IMAP_SERVER"/>
<subclass name="POP3Server" extends="com.mail.account.IncomingMailServer"
discriminator-value="POP3_SERVER"/>
<subclass name="SMTPServer" extends="com.mail.account.OutgoingMailServer"
discriminator-value="SMTP_SERVER" />
类层次结构
抽象类:
MailServer
是一个抽象类IncomingServer
是一个抽象类:这有助于不指定DISCRIMINATOR VALUE
OutgoingServer
是一个抽象类:这有助于不指定DISCRIMINATOR VALUE
具体类:
IMAPServer
使用DISCRIMINATOR VALUE : IMAP
扩展 IncomingServerPOP3Server
使用DISCRIMINATOR VALUE : POP3
扩展 IncomingServerSMTPServer
使用DISCRIMINATOR VALUE : SMTP
扩展 IncomingServer
所有具体服务器都映射到同一个表“SERVER”,但是如果需要,可以使用连接表将它们映射到单独的表。
代码片段
我能够使用以下简单的代码片段保存实例:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction txn =session.beginTransaction();
IMAPServer imap=new IMAPServer();
imap.setAddress("SMTP_01");
imap.setPortNumber("SMTP_PORT_0001");
session.save(imap);
SMTPServer smtp=new SMTPServer();
smtp.setAddress("STMP_01");
smtp.setPortNumber("STMP_PORT_0001");
session.save(smtp);
MailAccount account=new MailAccount();
account.setIncomingServer(imap);
account.setOutgoingServer(smtp);
session.save(account);
txn.commit();
请告诉我这是否可以解决问题。 :)
编辑:添加了从 MailAccount 到 MailServer 的映射。
<class name="MailAccount" table="MAILACCOUNT" dynamic-update="true">
<id name="id" column="id">
<generator class="native" />
</id>
<many-to-one name="incomingServer" column="incoming" unique="true"/>
<many-to-one name="outgoingServer" column="outgoing" unique="true"/>
</class>
关于 hibernate : "InstantiationException: Cannot instantiate abstract class or interface",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7502455/