Java 休眠且无PK
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/767277/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Hibernate and no PK
提问by Schildmeijer
Is it possible to create a table (from a JPA annotated Hibernate @Entity
) that does not contain a primary key / Id?
是否可以创建一个@Entity
不包含主键/Id的表(来自 JPA 注释的 Hibernate )?
I know this is not a good idea; a table should have a primary key.
我知道这不是一个好主意;一个表应该有一个主键。
采纳答案by Schildmeijer
I found that its not possible to do so. So bad luck for those working with legacy systems.
我发现这是不可能的。对于那些使用遗留系统的人来说运气太差了。
If you reverse engineer (create JPA annotated entities from existing JDBC connection) the table will create two Java classes, one Entity and with one field; id, and one embeddable id containing all the columns from your relation.
如果您进行逆向工程(从现有 JDBC 连接创建 JPA 注释实体),该表将创建两个 Java 类,一个实体和一个字段;id,以及一个包含关系中所有列的可嵌入 id。
回答by awied
Roger's self-answer is correct. To elaborate a bit on what is meant (I wasn't clear on it at first and figured this would help):
罗杰的自我回答是正确的。详细说明一下是什么意思(我一开始并不清楚,认为这会有所帮助):
Say you have you have a table Foo as such:
假设你有一个这样的表 Foo:
TABLE Foo (
bar varchar(20),
bat varchar(20)
)
Normally, you can write a class w/Annotations to work with this table:
通常,您可以编写一个带注释的类来处理此表:
// Technically, for this example, the @Table and @Column annotations
// are not needed, but don't hurt. Use them if your column names
// are different than the variable names.
@Entity
@Table(name = "FOO")
class Foo {
private String bar;
private String bat;
@Column(name = "bar")
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
@Column(name = "bat")
public String getBat() {
return bat;
}
public void setBat(String bat) {
this.bat = bat;
}
}
.. But, darn. This table has nothing we can use as an id, and it's a legacy database that we use for [insert vital business function]. I don't think they'll let me start modifying tables in order for me to use hibernate.
.. 但是,该死的。该表没有任何我们可以用作 id 的内容,它是我们用于 [插入重要业务功能] 的遗留数据库。我认为他们不会让我开始修改表格以便我使用休眠。
You can, instead, split the object up into a hibernate-workable structure which allows the entire row to be used as the key. (Naturally, this assumes that the row is unique.)
相反,您可以将对象拆分为一个休眠可用的结构,该结构允许将整行用作键。(当然,这假定该行是唯一的。)
Split the Foo object into two thusly:
如此将 Foo 对象一分为二:
@Entity
@Table(name = "FOO")
class Foo {
@Id
private FooKey id;
public void setId(FooKey id) {
this.id = id;
}
public void getId() {
return id;
}
}
and
和
@Embeddable
class FooKey implements Serializable {
private String bar;
private String bat;
@Column(name = "bar")
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
@Column(name = "bat")
public String getBat() {
return bat;
}
public void setBat(String bat) {
this.bat = bat;
}
}
}
.. And that should be it. Hibernate will use the Embeddable key for its required identity and you can make a call as normal:
.. 应该就是这样。Hibernate 将使用 Embeddable 密钥作为其所需的身份,您可以正常拨打电话:
Query fooQuery = getSession().createQuery("from Foo");
Hope this helps first-timers with getting this working.
希望这有助于第一次使用它。
回答by Domenic D.
You don't need to create a separate class to be your @Id or Primary Key. Just use an Integer (or whatever). Also, don't publish the fake key as developers who use it might think it's real and otherwise try to use it. Lastly, this is best used in a VIEW. I agree with earlier posts that in most, if not all cases, tables should have a primary key. For example:
您不需要创建一个单独的类来作为您的 @Id 或主键。只需使用整数(或其他)。此外,不要发布假密钥,因为使用它的开发人员可能会认为它是真实的,否则会尝试使用它。最后,这最好在 VIEW 中使用。我同意之前的帖子,在大多数情况下,如果不是所有情况,表应该有一个主键。例如:
@Entity
@Table(name = "FOO")
class Foo {
@SuppressWarnings("unused")
@Id
private Integer id;
@Column(name = "REAL_COLUMN")
private String realColumn;
public String getRealColumn() {
return realColumn;
}
public void setRealColumn(String realColumn) {
this.realColumn= realColumn;
}
}
回答by Amit
Use following code; Hibernate doesn't have its own logic to distinguish duplicate records
使用以下代码;Hibernate 没有自己的逻辑来区分重复记录
Let me know if there are any issues with this approach
如果这种方法有任何问题,请告诉我
@Entity @IdClass(Foo.class)
class Foo implements Serializable {
@Id private String bar;
@Id private String bat;
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
public String getBat() {
return bat;
}
public void setBat(String bat) {
this.bat = bat;
}
}
回答by Kuldeep
To Create the Pojo from table - use the reverse Engineering method existing in eclipse. For the non- primary key table, eclipse will generate the two Pojo classes.
从表创建 Pojo - 使用 eclipse 中存在的逆向工程方法。对于非主键表,eclipse 会生成两个 Pojo 类。
eclipse generated class and hbm.xml -
---
Foo.java
//
public class Foo implements java.io.Serializable {
private FooId id;
public Foo() {
}
public Foo(FooId id) {
this.id = id;
}
public FooId getId() {
return this.id;
}
public void setId(FooId id) {
this.id = id;
}
}
---
FooId.java
//
public class FooId implements java.io.Serializable {
private String bar;
private String bat;
public FooId() {
}
public FooId(String bar, String bat) {
this.bar = bar;
this.bat = bat;
}
public String getBar() {
return this.bar;
}
public void setBar(String bar) {
this.bar = bar;
}
public String getBat() {
return this.bat;
}
public void setBat(String bat) {
this.bat = bat;
}
public boolean equals(Object other) {
if ((this == other))
return true;
if ((other == null))
return false;
if (!(other instanceof FooId))
return false;
FooId castOther = (FooId) other;
return ((this.getBar() == castOther.getBar()) || (this.getBar() != null
&& castOther.getBar() != null && this.getBar().equals(
castOther.getBar())))
&& ((this.getBat() == castOther.getBat()) || (this.getBat() != null
&& castOther.getBat() != null && this.getBat().equals(
castOther.getBat())));
}
public int hashCode() {
int result = 17;
result = 37 * result
+ (getBar() == null ? 0 : this.getBar().hashCode());
result = 37 * result
+ (getBat() == null ? 0 : this.getBat().hashCode());
return result;
}
}
---
Foo.hbm.xml
<hibernate-mapping>
<class name="com.Foo" table="foo" schema="public" catalog="hibernate_poc">
<composite-id name="id" class="com.FooId">
<key-property name="bar" type="string">
<column name="bar" length="20" />
</key-property>
<key-property name="bat" type="string">
<column name="bat" length="20" />
</key-property>
</composite-id>
</class>
</hibernate-mapping>
---
entry in the Hibernate.cfg.xml -
<mapping class="com.poc.Foo" resource="Foo.hbm.xml"/>
---
Fetch the Data from table -
FooDataFetch.java
//
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class FooDataFetch {
private static Session session = null;
public static void main(String[] args) {
try{
Configuration cfg = new Configuration();
cfg.configure("/hibernate.cfg.xml");
SessionFactory sf = cfg.buildSessionFactory();
session = sf.openSession();
session.beginTransaction();
queryPerson(session);
session.close();
}catch (Throwable ex) {
System.err.println("Failed to create sessionFactory object." + ex);
ex.printStackTrace();
throw new ExceptionInInitializerError(ex);
}
}
private static void queryPerson(Session session) {
Query query = session.createQuery("from Foo");
List <Foo>list = query.list();
java.util.Iterator<Foo> iter = list.iterator();
while (iter.hasNext()) {
Foo foo = iter.next();
System.out.println("Foo Details: \"" + foo.getId().getBar() +"\", " + foo.getId().getBat());
}
}
}
回答by punkck
Adding to Awied's comment. If then you want to search for a bar, use following HQL.
添加到 Awied 的评论中。如果您想搜索柱状图,请使用以下 HQL。
Query fooQuery = getSession().createQuery("from Foo.id.bar = '<barName>'");
回答by RudiDudi
i found that this trick works:
我发现这个技巧有效:
<id column="ROWID" type="string" />
回答by Kanaris007
I have found solution for tables without primary key and null as values. It will work on oracle DB. Maybe something similar exists for other DBs.
我找到了没有主键和 null 作为值的表的解决方案。它将在 oracle DB 上工作。也许其他数据库也存在类似的东西。
You should create new primary key in the POJO class:
@Id @Column(name="id") private Integer id;
您应该在 POJO 类中创建新的主键:
@Id @Column(name="id") 私有整数 id;
and use createNativeQuery like this
并像这样使用 createNativeQuery
getEntityManager().createNativeQuery("select rownum as id, .....
The native query will generate primary key and you will get unique results.
本机查询将生成主键,您将获得唯一的结果。
回答by luke
When it comes to views instead of searching for workarounds in Hibernate it might be easier to add dummy id in your database view. I wrote about it in another question: https://stackoverflow.com/a/44050230/1673775
当涉及到视图而不是在 Hibernate 中搜索解决方法时,在数据库视图中添加虚拟 id 可能更容易。我在另一个问题中写道:https: //stackoverflow.com/a/44050230/1673775
回答by Nazmul Hoque Shafin
Though ROWID is a pseudo-column,yet as ROWID corresponds to the physical address of a ROW, it is the quickest mean to retrieve any row data. As @Id is used to identify the object uniquely and ROWID is unique inside a table, we can exploit it to overcome the issue we are discussing about. Actually, if we don't need any meaningful unique identifier, ROWID is the best column to annotate with @Id annotation as it corresponds to the physical address of the row. The following code worked for me.
@Id
@Column(name = "ROWID")
private String Id;
虽然 ROWID 是一个伪列,但由于 ROWID 对应的是一个 ROW 的物理地址,所以它是检索任何行数据的最快方法。由于@Id 用于唯一标识对象,而 ROWID 在表中是唯一的,我们可以利用它来解决我们正在讨论的问题。实际上,如果我们不需要任何有意义的唯一标识符,ROWID 是使用 @Id 注释的最佳列,因为它对应于行的物理地址。以下代码对我有用。
@Id
@Column(name = "ROWID")
private String Id;