Неправильный SQL для просмотра объекта с использованием аннотаций гибернации
-
10-07-2019 - |
Вопрос
Я работаю над отображением объектов в режиме гибернации для представления базы данных;когда я выполняю запрос критериев к нему, hibernate генерирует неверный SQL.Буду очень признателен за любую помощь в выяснении, в чем проблема с моим отображением!
У меня есть две сопоставленные сущности, которые я пытаюсь извлечь из представления базы данных;в представлении нет других столбцов, только FK каждого объекта.Один из этих FK можно рассматривать как первичный ключ, поскольку в представлении есть строка для каждого первичного объекта.Итак, моя схема базы данных для представления выглядит следующим образом:
primary(primary_id, some_other_fields)
history(history_id, primary_id, some_other_fields)
view_latest_status_history(primary_id, history_id)
Обратите внимание, что представление используется потому, что я хочу выбрать только последнюю историю для каждой основной, а не для всех отображенных записей истории.Вот объект, который я использую для представления, с аннотациями объектов:
@Entity
@org.hibernate.annotations.Entity(dynamicUpdate = true)
@Table(name = "view_latest_status_history")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class ViewLatestStatusHistoryRow implements Serializable {
private Primary primary;
private History history;
/**
* @return Returns the history.
*/
@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, fetch = FetchType.LAZY)
@JoinColumn(name = "history_id", nullable = true)
@AccessType("field")
public History getHistory() {
return history;
}
//equals() and hashCode() implementations are omitted
/**
* @return Returns the primary.
*/
@Id
@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, fetch = FetchType.LAZY)
@JoinColumn(name = "primary_id", nullable = false)
@AccessType("field")
public Primary getPrimary() {
return primary;
}
}
Как первичный объект, так и объект Истории имеют полные аннотации к рабочим объектам.
Настройка моих критериев:
criteria.add(Restrictions.in("primary", [collection of primary objects]));
criteria.setFetchMode("primary", FetchMode.JOIN);
criteria.setFetchMode("history", FetchMode.JOIN);
И (неправильно) сгенерированный SQL:
select this_.primary as primary78_1_, this_.primary_id as prim2_78_1_, primary2_.history_id as unique1_56_0_, ...history fields
from DB_CATALOG.dbo.view_latest_status_history this_
left outer join DB_CATALOG.dbo.history primary2_ on this_.primary_id=primary2_.primary_id
where this_.specChange in (?, ?...)
Возможно, я что-то напутал при редактировании специфики схемы базы данных нашего проекта, но дело в том, что первое поле в предложении 'select' неверно:
this_.primary (view_latest_status_history.primary) не является полем;поле должно называться primary_id.Я думаю, это может иметь какое-то отношение к аннотации @Id в основном поле?Есть идеи, как это исправить?Если я удалю @Id, я получу сообщение об ошибке, сообщающее мне, что у объекта нет первичного ключа.
Обновить:
Я больше не отображаю представление как поле, используя обозначение таблицы объединения (как предложено ниже).Примечания были пересмотрены следующим образом.Это решение корректно работает в HQL и генерирует ожидаемую схему, когда включен hbm2ddl, но я не тестировал его повторно с помощью запроса criteria.
@Entity
@Table(name = "view_latest_status_history")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class ViewLatestStatusHistoryRow implements Serializable {
private String id;
private Primary primary;
private History history;
/**
* @return Returns the history.
*/
@OneToOne(optional = true)
@JoinColumn(name = "history_id", nullable = true)
@AccessType("field")
public History getHistory() {
return history;
}
//equals() and hashCode() implementations are omitted
@Id
@Column(name = "primary_id", nullable = false)
@Override
@AccessType(value = "field")
public String getId() {
return id;
}
/**
* @return Returns the primary.
*/
@PrimaryKeyJoinColumn(name = "primary_id", referencedColumnName = "unique_id")
@OneToOne(optional = false)
@AccessType("field")
public Primary getPrimary() {
return primary;
}
}
Решение
Это, безусловно, связано с @Id
аннотация - primary_id в данном случае НЕ является первичным ключом.Также вы не можете реально использовать @Id и @ManyToOne в одном и том же свойстве.
Позвольте мне спросить вас вот о чем: зачем вы составляете карту ViewLatestStatusHistoryRow
как сущность с самого начала?Не похоже, что ты когда-нибудь будешь настаивать на этом.Рассмотрите возможность сопоставления вашей последней записи истории напрямую (как доступной только для чтения) с первичной (как много-к-одному) и использования вашего представления в качестве таблицы соединений.