问题描述
|
我目前正在尝试用Hibernate替换自己的数据库控制器实现,并且在创建适当的映射文件时遇到以下问题。
(我对Hibernate还是很陌生,所以请保持谨慎:-)-我已经阅读了整个《 Hibernate参考》文档,但是我没有任何实践经验。
(整个过程应该表示电子邮件帐户与其服务器设置之间的关系)。
我有一个名为MailAccount的类,它具有2个属性(请参见下面的代码):
public class MailAccount{
long id;
IncomingMailServer incomingServer;
OutgoingMailServer outgoingServer;
public MailAccount(){
super();
}
// Getter and setter omitted
}
服务器类hierachy如下所示:
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中的传入服务器和传出服务器属性仅包含Pop3Server,ImapServer(对于传入服务器)或SmtpServer(对于outingServer)的实例。
现在,我尝试为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)的实例而不是抽象的实例?
示例:如果属性传入服务器包含Pop3Server的实例,则Hiberante应该将该实例存储到我的数据库中,当我重新加载相应的MailAccount时,我希望Hibernate重新创建Pop3Server的实例。
解决方法
发生问题的原因是组件不是独立实体,而是\“is9ѭ\”。在JPA术语中,它被视为可嵌入类。这些类通常用于从许多表列中创建一个类对象,这些表列通常必须作为单独的属性存储在实体中(您几乎可以将其视为分组)。
尽管此方法有很多好处,但还是有一些限制。这些限制之一是组件或可嵌入组件不能是抽象类。原因是休眠没有任何方式将特定的具体子类与您尝试存储或读取的值相关联。这样想:您是否仅通过查看列数据就能知道要创建哪个实例?通常情况并非如此,特别是对于持久性引擎。
为了获得所需的功能,您将需要考虑将MailServer数据存储为具有其自己的主键字段的单独实体。这样做可以使您使用各种继承方法(例如,包含DiscriminatorColumn或单独的表(取决于您的配置))使用子类管理数据。
以下是一些链接,它们可以帮助您设置这些映射和使用实体继承:
一对一映射示例
(如果不重复使用
MailServer
很有用
数据。
继承概述
有用的Hibernate示例(不是
最新的规格,但给你很好
概述)
希望这可以帮助。
http://www.vaannila.com/hibernate/hibernate-example/hibernate-example.html
如果要使用Hibernate的这种方法(我个人更喜欢基于JPA的Annotation配置),则可以将MailServer
配置为抽象实体,该实体将定义类和DiscriminatorColumn之间的公共列映射(如果使用相同的表继承)。子类将基于此定义构建,并根据需要添加自定义属性。