Какой самый умный способ получить сущность с полем типа List сохраняется?
Command.java
package persistlistofstring;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Persistence;
@Entity
public class Command implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@Basic
List<String> arguments = new ArrayList<String>();
public static void main(String[] args) {
Command command = new Command();
EntityManager em = Persistence
.createEntityManagerFactory("pu")
.createEntityManager();
em.getTransaction().begin();
em.persist(command);
em.getTransaction().commit();
em.close();
System.out.println("Persisted with id=" + command.id);
}
}
Этот код производит:
> Exception in thread "main" javax.persistence.PersistenceException: No Persistence provider for EntityManager named pu: Provider named oracle.toplink.essentials.PersistenceProvider threw unexpected exception at create EntityManagerFactory:
> oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException
> Local Exception Stack:
> Exception [TOPLINK-30005] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException
> Exception Description: An exception was thrown while searching for persistence archives with ClassLoader: sun.misc.Launcher$AppClassLoader@11b86e7
> Internal Exception: javax.persistence.PersistenceException: Exception [TOPLINK-28018] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.EntityManagerSetupException
> Exception Description: predeploy for PersistenceUnit [pu] failed.
> Internal Exception: Exception [TOPLINK-7155] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.ValidationException
> Exception Description: The type [interface java.util.List] for the attribute [arguments] on the entity class [class persistlistofstring.Command] is not a valid type for a serialized mapping. The attribute type must implement the Serializable interface.
> at oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:143)
> at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.createEntityManagerFactory(EntityManagerFactoryProvider.java:169)
> at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:110)
> at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:83)
> at persistlistofstring.Command.main(Command.java:30)
> Caused by:
> ...
Извините за восстановление старого потока, но если кто-то ищет альтернативное решение, где вы храните свои списки строк как одно поле в вашей базе данных, вот как я решил это. Создайте конвертер как это:
Теперь используйте его на ваших сущностях следующим образом:
В базе данных ваш список будет храниться как foo; bar; foobar, а в вашем Java-объекте вы получите список с этими строками.
Надеюсь, это кому-нибудь пригодится.
источник
SPLIT_CHAR
в вашей строке не должно быть ни одного вхождения.Этот ответ был сделан до реализации JPA2, если вы используете JPA2, см. Ответ ElementCollection выше:
Списки объектов внутри модельного объекта обычно рассматриваются как отношения «OneToMany» с другим объектом. Однако String (сам по себе) не является допустимым клиентом отношения «один ко многим», поскольку у него нет идентификатора.
Таким образом, вы должны преобразовать свой список строк в список объектов JPA класса Argument, содержащих идентификатор и строку. Потенциально вы можете использовать String в качестве идентификатора, что сэкономит немного места в вашей таблице как от удаления поля ID, так и за счет объединения строк, в которых строки равны, но вы потеряете возможность упорядочить аргументы обратно в исходный порядок. (так как вы не хранили никакой информации для заказа).
Кроме того, вы можете преобразовать свой список в @Transient и добавить другое поле (argStorage) в свой класс, которое будет либо VARCHAR (), либо CLOB. Затем вам нужно будет добавить 3 функции: 2 из них одинаковы и должны преобразовать ваш список строк в одну строку (в argStorage), разделенную таким образом, чтобы вы могли легко разделить их. Аннотируйте эти две функции (каждая из которых делает одно и то же) с помощью @PrePersist и @PreUpdate. Наконец, добавьте третью функцию, которая снова разбивает argStorage в список строк и аннотируйте ее @PostLoad. Это будет поддерживать ваш CLOB обновленным со строками всякий раз, когда вы сохраняете Команду, и обновлять поле argStorage, прежде чем сохранять его в БД.
Я все еще предлагаю сделать первый случай. Это хорошая практика для настоящих отношений позже.
источник
По словам Java Постоянство с Hibernate
Если бы вы использовали Hibernate, вы могли бы сделать что-то вроде:
Обновление: обратите внимание, теперь это доступно в JPA2.
источник
Мы также можем использовать это.
источник
У меня была та же проблема, поэтому я вложил возможное решение, но в конце я решил реализовать свой ';' разделенный список строк.
так что я
Таким образом, список легко читается / редактируется в таблице базы данных;
источник
arguments
представляет собой список разрешений доступа, то наличие специального символа aseparator
может быть уязвимым для атак на повышение привилегий.;
что сломает ваше приложение.При использовании реализации JPA в Hibernate, я обнаружил, что простое объявление типа как ArrayList вместо List позволяет hibernate хранить список данных.
Очевидно, что это имеет ряд недостатков по сравнению с созданием списка объектов Entity. Нет ленивой загрузки, нет возможности ссылаться на объекты в списке из других объектов, возможно, больше сложностей при построении запросов к базе данных. Однако, когда вы имеете дело со списками довольно примитивных типов, которые вы всегда захотите получить вместе с сущностью, тогда этот подход мне подходит.
источник
@OneToMany
@ManyToOne
@ElementCollection
он даст вамCaused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements
исключение при запуске сервера. Потому что hibernates хочет, чтобы вы использовали интерфейсы коллекций.Кажется, что ни один из ответов не исследовал наиболее важные настройки для
@ElementCollection
сопоставления.Когда вы сопоставляете список с этой аннотацией и позволяете JPA / Hibernate автоматически генерировать таблицы, столбцы и т. Д., Он также будет использовать автоматически сгенерированные имена.
Итак, давайте проанализируем базовый пример:
@ElementCollection
аннотация (где вы можете определить известныеfetch
иtargetClass
предпочтения)@CollectionTable
Аннотация очень полезно , когда речь идет , чтобы дать имя таблицы , которая будет сгенерирована, а также определения , какjoinColumns
,foreignKey
«s,indexes
,uniqueConstraints
и т.д.@Column
Важно определить имя столбца, в котором будет хранитьсяvarchar
значение списка.Созданное создание DDL будет:
источник
Хорошо, я знаю, что немного поздно. Но для тех смельчаков, которые увидят это с течением времени.
Как написано в документации :
Важной частью является тип, который реализует Сериализуемый
Таким образом, на сегодняшний день самым простым и простым в использовании решением является просто использование ArrayList вместо List (или любого сериализуемого контейнера):
Однако помните, что при этом будет использоваться сериализация системы, поэтому она будет стоить дорого, например:
если изменится сериализованная объектная модель, вы не сможете восстановить данные
небольшие накладные расходы добавляются для каждого хранимого элемента.
Коротко
хранить флаги или несколько элементов довольно просто, но я бы не советовал хранить данные, которые могут стать большими.
источник
Тиаго ответ правильный, добавив образец, более специфичный для вопроса, @ElementCollection создаст новую таблицу в вашей базе данных, но без сопоставления двух таблиц. Это означает, что коллекция - это не коллекция сущностей, а коллекция простых типов (строки и т. Д.). .) или набор встраиваемых элементов (класс, аннотированный @Embeddable ).
Вот пример для сохранения списка строк
Вот пример для сохранения списка пользовательских объектов
Для этого случая нам нужно сделать класс Embeddable
источник
Вот решение для хранения набора с использованием @Converter и StringTokenizer. Еще немного проверок против решения @ jonck-van-der-kogel .
В вашем классе Entity:
StringSetConverter:
источник
Мое исправление для этой проблемы состояло в том, чтобы отделить первичный ключ от внешнего ключа. Если вы используете eclipse и внесли вышеуказанные изменения, пожалуйста, не забудьте обновить проводник базы данных. Затем воссоздайте сущности из таблиц.
источник