Возможно ли создать таблицу (из JPA аннотированного Hibernate @Entity
), которая не содержит первичный ключ /Id?
Я знаю, что это не очень хорошая идея; таблица должна иметь первичный ключ.
Возможно ли создать таблицу (из JPA аннотированного Hibernate @Entity
), которая не содержит первичный ключ /Id?
Я знаю, что это не очень хорошая идея; таблица должна иметь первичный ключ.
Я обнаружил, что это невозможно сделать. Настолько неудача для тех, кто работает с устаревшими системами.
Если вы перепроектируете (создаете аннотированные объекты JPA из существующего соединения JDBC), таблица создаст два класса Java, одну Entity и одно поле; id и один внедряемый id, содержащий все столбцы из вашего отношения.
Автоответчик Роджера правильный. Чтобы немного рассказать о том, что имеется в виду (сначала я не понял его и подумал, что это поможет):
Скажем, у вас есть таблица Foo как таковая:
TABLE Foo (
bar varchar(20),
bat varchar(20)
)
Обычно вы можете написать класс w/Annotations для работы с этой таблицей:
// 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, и это устаревшая база данных, которую мы используем для [вставки важной бизнес-функции]. Я не думаю, что они позволят мне начать изменять таблицы, чтобы я мог использовать спящий режим.
Вместо этого вы можете разбить объект на рабочую структуру с гибернацией, которая позволяет использовать всю строку в качестве ключа. (Естественно, это предполагает, что строка уникальна.)
Разделите объект 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");
Надеемся, что это поможет первоклассникам с этим работать.
Использовать следующий код; 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;
}
}
Я обнаружил, что этот трюк работает:
<id column="ROWID" type="string" />
Вам не нужно создавать отдельный класс для вашего @Id или основного ключа. Просто используйте Integer (или что-то еще). Кроме того, не публикуйте поддельный ключ, так как разработчики, которые его используют, могут подумать, что это реально и в противном случае пытаются его использовать. Наконец, это лучше всего использовать в 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;
}
}
Создать 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());
}
}
}
Добавление в комментарий Awied. Если вы хотите найти панель, используйте следующий HQL.
Query fooQuery = getSession().createQuery("from Foo.id.bar = '<barName>'");
Когда дело доходит до представлений вместо поиска обходных путей в Hibernate, может быть проще добавить фиктивный идентификатор в вашем представлении базы данных. Я написал об этом в другом вопросе: fooobar.com/questions/115565/...
Я нашел решение для таблиц без первичного ключа и null в качестве значений. Он будет работать на базе Oracle. Возможно, что-то подобное существует для других БД.
Вы должны создать новый первичный ключ в классе POJO:
@Id @column (name= "идентификатор" ) private Integer id;
и используйте createNativeQuery, подобный этому
getEntityManager().createNativeQuery("select rownum as id, .....
Собственный запрос будет генерировать первичный ключ, и вы получите уникальные результаты.