Как сопоставить представление базы данных без первичного ключа при использовании JPA

  • У меня есть представления в базе данных SQL без очевидного первичного ключа (составного или иного)
  • Я хотел бы получить к ним доступ через JPA

Я читал, что должен иметь возможность обрабатывать представления в JPA так же, как я обрабатываю таблицы (используя аннотацию @Table и т. д.). Однако без первичного ключа я должен эффективно создавать составной ключ из КАЖДОЙ СТОЛБЦЫ (фактически, это то, что по умолчанию делает инструмент обратного проектирования Hibernate).

Однако, если я это сделаю, возникнут нежелательные побочные эффекты. Например.

  • Необходимо написать весь код, указывающий на атрибуты первичного ключа, а не на представления:

    myViewObject.getPrimaryKey().getFirstName()

  • Невозможно использовать методы "findBy..." в репозитории Spring (поскольку этот атрибут является частью "идентификатора" представления, а не одним из его атрибутов).

Мой вопрос: как мне сопоставить представления таким образом, чтобы я мог легко получить доступ к их атрибутам с помощью JPA?

Примечание. Я очень рад узнать, что я использую совершенно неправильный подход. Кажется, это настолько распространенная проблема, что должно быть лучшее решение.


person Andy N    schedule 08.07.2015    source источник
comment
Один трюк, который я использую, заключается в анализе возможных запросов в представлении, чтобы увидеть, сколько из них могут вернуть несколько записей, и посмотреть, есть ли поле, которое останется уникальным для всех записей во всех этих ситуациях. Если вы можете найти такой сценарий, вы можете назначить это поле первичным ключом, даже если на самом деле это не первичный ключ, поскольку ORM заботится только об уникальности среди результатов одного запроса. Но учтите, что вы не сможете использовать кеш второго уровня. В тех случаях, когда этот трюк неприменим, я изменяю запрос для представления, чтобы включить первичный ключ.   -  person manish    schedule 08.07.2015
comment
Ничто не мешает вам писать методы делегирования, такие как getFirstName(), который делает return this.getPrimaryKey().getFirstName(). Тогда вам нужно написать длинную версию только один раз. Что касается неправильного подхода, у нас в приложении более 400 объектов/таблиц, и у нас нет ни одного View-Entity. Однажды я попытался использовать его, потому что думал, что это поможет, но он начал вызывать проблемы, поэтому я создал такое же «представление» в JPQL, которое выполняло ту же работу и давало мне больше гибкости.   -  person DuncanKinnear    schedule 09.07.2015


Ответы (1)


Вы можете добавить столбец UUID в каждую строку представлений, чтобы затем использовать столбец UUID в качестве @Id.

person Vlad Mihalcea    schedule 08.07.2015
comment
Да, это сработало, спасибо. Я изменил свои (Oracle) представления, включив в них дополнительный столбец: sys_guid() AS uuid Затем добавил следующее свойство вверху моего представления @Entity: @Id @Column(name="UUID") @JsonIgnore protected String uuidHex; - person Andy N; 08.07.2015
comment
Энди, я бы предположил, что реализация решения ошибочна. UUID будет отличаться для каждого запроса. По сути, это действительный идентификатор, но я бы не ожидал, что смогу выбрать Entity A по заданному UUID более одного раза, т.е. вы не сможете перейти от списка объектов к одному объекту. Таким образом, этот UUID должен быть частью одной из базовых таблиц и фактически храниться как столбец, а не вычисляться в представлении. Альтернативой может быть использование материализованных представлений. - person Michael Simons; 08.07.2015
comment
Наоборот, это именно то, что мне было нужно для решения проблемы. Моя проблема заключалась в том, что не было очевидного первичного ключа (см. Выше). Представьте себе набор столбцов чистых данных, некоторые или все из которых могут быть нулевыми (что достаточно типично для баз данных SQL). Мне пришлось ИСКУССТВЕННО дать им ПК, чтобы спящий режим оставался счастливым. Добавление сгенерированного UUID в запрос удовлетворяло этим критериям. Навигация никогда не была вариантом. - person Andy N; 09.07.2015
comment
добавление @Immutable к Entity тоже будет работать? просто представьте, что у вас нет доступа к представлению, и вам нужно сопоставить его с сущностью, тогда добавление @Immutable будет работать? - person Mohammad Eghlima; 07.05.2019
comment
@MohammadEghlima: Нет, вы получите ошибку org.hibernate.AnnotationException: No identifier specified for entity: <entity>. - person Jacob van Lingen; 20.02.2020