我目前正在尝试用Hibernate替换我自己的数据库控制器实现,并且我在创建适当的映射文件时遇到以下问题。
(我对Hibernate很新,所以请温柔:-) - 我已经阅读了整个Hibernate Reference文档,但我还没有任何实际经验。)
(整个事情应代表电子邮件帐户与其服务器设置之间的关系)。
我有一个名为MailAccount的类,它有2个属性(参见下面的代码):
public class MailAccount{
long id;
IncomingMailServer incomingServer;
OutgoingMailServer outgoingServer;
public MailAccount(){
super();
}
// Getter and setter omitted
}
服务器类层次结构如下所示:
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();
}
}
MailAccount.java中的incomingServer和outgoingServer属性当然只包含Pop3Server,ImapServer(对于incomingServer)或SmtpServer(对于outgoingServer)的实例。
现在,我尝试为MailAccount创建映射文件:
<?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="test.account">
<class name="MailAccount" table="MAILACCOUNTS" dynamic-update="true">
<id name="id" column="MAIL_ACCOUNT_ID">
<generator class="native" />
</id>
<component name="incomingServer" class="test.server.incoming.IncomingMailServer">
<property name="password" column="INCOMING_SERVER_PASSWORD" />
<property name="host" column="INCOMING_SERVER_PASSWORD" />
<property name="username" column="INCOMING_SERVER_PASSWORD" />
<property name="port" column="INCOMING_SERVER_PASSWORD" />
</component>
<component name="outgoingServer" class="test.server.outgoing.OutgoingMailServer">
<property name="password" column="OUTGOING_SERVER_PASSWORD" />
<property name="host" column="OUTGOING_SERVER_PASSWORD" />
<property name="username" column="OUTGOING_SERVER_PASSWORD" />
<property name="port" column="OUTGOING_SERVER_PASSWORD" />
</component>
</class>
</hibernate-mapping>
注意:由于我在MailAccount和IncomingMailServer以及MailAccount和OutgoingMailServer之间建立了1:1的关系,我希望1表中的所有内容都能防止不必要的连接。
问题:每当我告诉Hibernate保存一个MailAccount实例时,就像这样:
session = getSession();
transaction = session.beginTransaction();
session.save(mailAccount);
transaction.commit();
..我收到以下异常:
org.hibernate.InstantiationException: 无法实例化抽象类或 接口: test.server.incoming.IncomingMailServer
这完全有道理,因为抽象类无法实例化。
然而,这里是我的问题:我如何告诉Hibernate创建一个正确类的实例(Pop3Server,SmtpServer,ImapServer)而不是抽象的实例?
示例:如果属性incomingServer拥有Pop3Server的实例,那么Hiberante应该将其存储到我的数据库中,当我加载相应的MailAccount时,我希望Hibernate重新创建Pop3Server的实例。 / p>
答案 0 :(得分:4)
问题出现是因为组件不是独立的实体,而是“a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity
”。在JPA术语中,它被认为是Embeddable类。这些类通常用于从多个表列中创建一个类对象,这些表通常必须作为单个属性存储在实体中(您几乎可以将其视为分组)。
虽然这种方法有很多好处,但也存在一些限制。其中一个限制是组件或嵌入式不能是抽象类。原因是hibernate没有办法将特定的具体子类与您尝试存储或读取的值相关联。可以这样想一想:您是否能够通过查看列数据来判断要创建的实例?它通常不是那么直接,特别是对于持久性引擎。
为了获得您想要的功能,您需要考虑将MailServer数据存储为具有自己的主键字段的单独实体。这样做允许您使用各种继承方法管理子类的数据,例如包括DiscriminatorColumn或单独的表(取决于您的配置)。
以下是一些可以帮助您设置这些映射和使用实体继承的链接:
MailServer
则很有用
数据。 希望这有帮助。
http://www.vaannila.com/hibernate/hibernate-example/hibernate-example.html
如果你使用Hibernate使用这种方法(我个人更喜欢基于JPA的Annotation配置),你可以将MailServer
配置为一个抽象实体,它将定义类和DiscriminatorColumn之间的公共列映射(如果使用相同的表继承)。子类将根据此定义构建,根据需要添加自定义属性。