我在Oracle数据库中有旧表,我想使用Hibernate从Java应用程序访问它。问题是:表没有好的主键。例如,一个表如下所示:
create table employee (
first_name varchar(64) not null,
last_name varchar(64) not null,
hired_at date,
department varchar(64)
);
create unique index emp_uidx on employee (firstname, lastname, hired_at);
最初的设计师决定使用该hired_at
列作为状态字段,认为数据库永远不需要区分公司外部的John
Smiths,而是可以通过他们的hired_at日期来识别具有相同名称的员工。显然,这将创建一个部分可为空且可修改的主键。由于数据库不允许将此作为主键,因此他使用了唯一索引。
现在,如果我尝试为此编写一个Hibernate映射,则可以想到以下内容:
<hibernate-mapping>
<class name="com.snakeoil.personnel" table="employee">
<composite-id class="com.snakeoil.personnel.EmpId" name="id">
<key-property name="firstName" column="first_name" type="string"/>
<key-property name="lastName" column="last_name" type="string"/>
</composite-id>
<property name="hiredAt" column="hired_at" type="date"/>
<property name="department" type="string">
</class>
</hibernate-mapping>
这适用于读取数据,但是当我创建仅在其hiredAt日期不同的新条目时,我遇到了org.hibernate.NonUniqueObjectExceptions。或者,我可能考虑使用Oracle的ROWID功能:
<id column="ROWID" name="id" type="string">
<generator class="native"/>
</id>
这对于读取数据也很好。但是显然,您不能持久化新对象,因为Hibernate现在会抛出org.hibernate.exception.SQLGrammarException:在尝试存储实体时无法获取下一个序列值。
解决此问题的明显方法是通过代理键。但是,那将需要更改数据库架构,这使我们回到了“传统”的东西。
我在俯视什么?有没有办法使Hibernate与Oracle的ROWID协作,也许与其他生成器协作?还是有办法使第一个想法起作用,也许是通过巧妙的DAO来逐出并重新加载实体,并从应用程序中隐藏复杂性?还是我应该寻找Ibatis的Hibernate替代产品?
您不想用ROWID
作主键,因为不能保证它在行的整个生命周期内都是稳定的。
最好添加一个合成密钥。使用触发器用序列值填充列。
您在遗留方面有点含糊,因此很难确定其含义。添加列将破坏任何未显式列出目标列的插入语句。它也可能会打断任何SELECT *
查询(除非它们选择使用%ROWTYPE
关键字声明的变量。但是您不必更改任何其他应用程序,因此它使用新的主键而不是现有的列-除非您确实愿意。
问题内容: 据我了解,每当我在JPA / Hibernate实体内的Long字段上使用@Id和@GeneratedValue时,我实际上是在使用代理键,考虑到我的非母语,这是定义主键的一种非常不错的方法- 使用复合主键的良好经验,其中: 有不止一种业务-价值-行业组合成为唯一的PK 组合pk值在表详细信息中重复 无法更改该复合PK内的业务价值 我知道休眠可以支持两种类型的PK,但是我以前与有经验的
问题内容: 据我了解,每当我在JPA / Hibernate实体内的Long字段上使用@Id和@GeneratedValue时,我实际上是在使用代理键,考虑到我的非以下方式,我认为这是定义主键的一种非常不错的方法- 使用复合主键的良好经验,其中: 有不止一种业务-价值-行业组合成为唯一的PK 组合pk值在表详细信息中重复 无法更改该复合PK内的业务价值 我知道hibernate可以支持这两种类型的
问题内容: 我有一个非常丑陋的旧数据库系统,需要与之集成。本质上,我在系统上做一些只读报告,并且我不想建立代表我正在处理的每个表的上千个实体。相反,我只想为我生成的每种报告类型定义一个实体(本质上是来自不同表的一堆列的并集),然后让讨厌的hibernate映射(许多已加入,很多已合并) sql查询到此类实体的列表。 问题是:我可以创建一个没有基础表的实体,并使用sql语句填充所述实体的列表吗? 谢
问题内容: 我使用Hibernate制作了一个示例应用程序。我的要求是表上没有主键。我只需要从应用程序中选择查询。我知道应该有一个主键,但是我所引用的表没有它。 它有大约5万条记录。因此,修改表以添加ID列将看不到可行的选项。 有可能吗 问题答案: Hibernate 要求 实体表具有主键。故事结局。 在谈论数据库时,5万条记录根本就不多。 我的建议:在表中添加一个自动增量整数PK列。您会对它的速
问题内容: 我必须在设计糟糕的旧数据库中应用JPA。不幸的是无法更改它。幸运的是,仅用于只读访问。 我发现的最奇怪的事情之一是没有联接(或中间)表的“多对多”关系。这是表结构的简化: ACCESS_GROUP列可以在两个表中重复 一位用户可以与N个访问相关 一个访问可以与N个用户相关 必须按照这种方式“概念上”将此表与Java类映射: 但是我认为这是不可能的。您认为在JPA中访问此表并进行浏览的最
问题内容: 我正在使用Hibernate 3.3.1,并正在对该示例表结构进行建模,但是在创建具有额外属性的联接表时遇到了麻烦。 是和表之间的多对多关系。联接表就是该表。我遵循这里提到的方法。 现在我有了实体 和 和 和 我使用Apache Derby进行测试,但是在生成的表结构上遇到了麻烦。 看来它已经创建了我所有的列作为主键。为什么会这样呢? 问题答案: 您可以使用实体的类作为IdClass的