是否可以创建一个不包含主键/ Id的表(来自JPA注释的Hibernate @Entity
)?
我知道这不是一个好主意;表应该有一个主键。
答案 0 :(得分:50)
罗杰的自我回答是正确的。详细说明一下是什么意思(我一开始并不清楚,并认为这会有所帮助):
假设你有一张桌子Foo:
TABLE Foo (
bar varchar(20),
bat varchar(20)
)
通常,您可以编写带有注释的类来使用此表:
// 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;
}
}
..但是,该死的。这个表没有我们可以用作id的东西,它是我们用于[插入重要业务功能]的遗留数据库。我不认为他们会让我开始修改表格以便我使用hibernate。
相反,您可以将对象拆分为休眠可操作的结构,该结构允许将整行用作键。 (当然,这假设行是唯一的。)
将Foo对象分成两部分:
@Entity
@Table(name = "FOO")
class Foo {
@Id
private FooKey id;
public void setId(FooKey id) {
this.id = id;
}
public void getId() {
return id;
}
}
和
@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;
}
}
..那应该是它。 Hibernate将使用Embeddable键作为其所需的身份,您可以正常拨打电话:
Query fooQuery = getSession().createQuery("from Foo");
希望这有助于第一次使用这项工作。
答案 1 :(得分:45)
使用以下代码; Hibernate没有自己的逻辑来区分重复记录
如果此方法存在任何问题,请告诉我
@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;
}
}
答案 2 :(得分:9)
我发现它不可能这样做。对那些使用遗留系统的人来说,运气不好。
如果您进行逆向工程(从现有JDBC连接创建JPA带注释的实体),该表将创建两个Java类,一个实体和一个字段; id,以及一个包含您关系中所有列的可嵌入ID。
答案 3 :(得分:9)
我发现这个技巧有效:
<id column="ROWID" type="string" />
答案 4 :(得分:2)
您无需创建单独的类作为@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;
}
}
答案 5 :(得分:1)
从表中创建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());
}
}
}
答案 6 :(得分:1)
添加到Awied的评论。 如果您想要搜索一个栏,请使用以下HQL。
Query fooQuery = getSession().createQuery("from Foo.id.bar = '<barName>'");
答案 7 :(得分:1)
当涉及到视图而不是在Hibernate中搜索变通方法时,在数据库视图中添加虚拟id可能更容易。我在另一个问题中写到了这一点:https://stackoverflow.com/a/44050230/1673775
答案 8 :(得分:0)
我找到了没有主键和null作为值的表的解决方案。它适用于oracle DB。也许其他数据库存在类似的东西。
您应该在POJO类中创建新的主键:
@Id @Column(名称=&#34; ID&#34) private Integer id;
并像这样使用createNativeQuery
getEntityManager().createNativeQuery("select rownum as id, .....
本机查询将生成主键,您将获得独特的结果。
答案 9 :(得分:0)
尽管ROWID是一个伪列,但是由于ROWID对应于ROW的物理地址,它是检索任何行数据的最快方法。由于@Id用于唯一标识对象,而ROWID在表中是唯一的,因此我们可以利用它来克服我们正在讨论的问题。实际上,如果我们不需要任何有意义的唯一标识符,则ROWID是使用@Id注释进行注释的最佳列,因为它对应于行的物理地址。以下代码对我有用。
@Id
@Column(name = "ROWID")
private String Id;