Jaki jest najmądrzejszy sposób na utrwalenie encji z polem typu 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);
}
}
Ten kod daje:
> 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:
> ...
Przepraszam, że przywracam stary wątek, ale jeśli ktoś szuka alternatywnego rozwiązania, w którym przechowujesz listy ciągów jako jedno pole w bazie danych, oto jak to rozwiązałem. Utwórz konwerter w następujący sposób:
Teraz użyj go na swoich Jednostkach w ten sposób:
W bazie danych Twoja lista będzie przechowywana jako foo; bar; foobar, aw obiekcie Java otrzymasz listę z tymi ciągami.
Mam nadzieję, że to komuś pomoże.
źródło
SPLIT_CHAR
wystąpień w swoim ciągu.Ta odpowiedź została utworzona przed implementacjami JPA2, jeśli używasz JPA2, zobacz odpowiedź ElementCollection powyżej:
Listy obiektów wewnątrz obiektu modelu są ogólnie uważane za relacje typu „OneToMany” z innym obiektem. Jednak String nie jest (sam w sobie) dopuszczalnym klientem relacji jeden-do-wielu, ponieważ nie ma identyfikatora.
Dlatego należy przekonwertować listę ciągów znaków na listę obiektów JPA klasy argumentów, zawierającą identyfikator i ciąg. Potencjalnie można użyć String jako identyfikatora, co pozwoliłoby zaoszczędzić trochę miejsca w tabeli zarówno przed usunięciem pola ID, jak i konsolidacją wierszy, w których ciągi są równe, ale straciłbyś możliwość uporządkowania argumentów z powrotem w ich pierwotnej kolejności (ponieważ nie zapisałeś żadnych informacji o zamówieniu).
Alternatywnie możesz przekonwertować swoją listę na @Transient i dodać kolejne pole (argStorage) do swojej klasy, które jest albo VARCHAR (), albo CLOB. Będziesz wtedy musiał dodać 3 funkcje: 2 z nich są takie same i powinny przekształcić twoją listę ciągów w pojedynczy ciąg (w argStorage) rozdzielony w sposób umożliwiający ich łatwe rozdzielenie. Dodaj adnotacje do tych dwóch funkcji (każda z nich robi to samo) za pomocą @PrePersist i @PreUpdate. Na koniec dodaj trzecią funkcję, która ponownie dzieli argStorage na listę ciągów znaków i dodaj do niej adnotację @PostLoad. Dzięki temu CLOB będzie aktualizowany za pomocą ciągów znaków za każdym razem, gdy przechodzisz do przechowywania polecenia, a pole argStorage będzie aktualizowane przed zapisaniem go w DB.
Nadal sugeruję zrobienie pierwszego przypadku. To dobra praktyka dla prawdziwych relacji później.
źródło
Według Java Persistence with Hibernate
Jeśli używałeś Hibernacji, możesz zrobić coś takiego:
Aktualizacja: Uwaga, jest to teraz dostępne w JPA2.
źródło
Możemy również tego użyć.
źródło
Korzystając z implementacji JPA Hibernate, odkryłem, że po prostu zadeklarowanie typu jako ArrayList zamiast List umożliwia hibernację do przechowywania listy danych.
Oczywiście ma to wiele wad w porównaniu do tworzenia listy obiektów Entity. Brak leniwego ładowania, brak możliwości odwoływania się do jednostek na liście z innych obiektów, być może większe trudności w tworzeniu zapytań do bazy danych. Jeśli jednak masz do czynienia z listami dość prymitywnych typów, które zawsze będziesz chciał chętnie pobrać wraz z bytem, to takie podejście wydaje mi się dobre.
źródło
@OneToMany
@ManyToOne
@ElementCollection
, da ci toCaused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements
wyjątek podczas uruchamiania serwera. Ponieważ hibernacja chce, abyś używał interfejsów kolekcji.Miałem ten sam problem, więc zainwestowałem w możliwe rozwiązanie, ale ostatecznie zdecydowałem się wdrożyć moje ';' oddzielona lista ciągów.
więc mam
W ten sposób lista jest łatwa do odczytania / edycji w tabeli bazy danych;
źródło
arguments
jest listą uprawnień dostępu, to posiadanie znaku specjalnego aseparator
, może być podatne na ataki eskalacji uprawnień.;
które spowodują uszkodzenie aplikacji.Wydaje się, że żadna z odpowiedzi nie dotyczyła najważniejszych ustawień
@ElementCollection
mapowania.Kiedy mapujesz listę z tą adnotacją i pozwalasz JPA / Hibernate automatycznie generować tabele, kolumny itp., Użyje również automatycznie wygenerowanych nazw.
Przeanalizujmy więc podstawowy przykład:
@ElementCollection
adnotacja (gdzie możesz zdefiniować znanefetch
itargetClass
preferencje)@CollectionTable
Adnotacja jest bardzo przydatna, jeśli chodzi o nadanie nazwy tabeli to będzie generowany, a także definicje, takie jakjoinColumns
,foreignKey
„s,indexes
,uniqueConstraints
, itd.@Column
ważne jest, aby zdefiniować nazwę kolumny, w której będzie przechowywanavarchar
wartość listy.Wygenerowane tworzenie DDL wyglądałoby tak:
źródło
Ok, wiem, że jest trochę za późno. Ale dla tych odważnych dusz, które zobaczą to w miarę upływu czasu.
Jak napisano w dokumentacji :
Ważną częścią jest typ, który implementuje Serializable
Zdecydowanie najprostszym i najłatwiejszym w użyciu rozwiązaniem jest po prostu użycie ArrayList zamiast List (lub dowolnego serializowalnego kontenera):
Pamiętaj jednak, że użyje to serializacji systemu, więc będzie to miało pewną cenę, taką jak:
jeśli serializowany model obiektów ulegnie zmianie, przywrócenie danych może nie być możliwe
mały narzut jest dodawany do każdego przechowywanego elementu.
W skrócie
przechowywanie flag lub kilku elementów jest dość proste, ale nie polecałbym tego do przechowywania danych, które mogą się rozrosnąć.
źródło
Odpowiedź Thiago jest poprawna, dodając próbkę bardziej szczegółową do pytania, @ElementCollection utworzy nową tabelę w twojej bazie danych, ale bez mapowania dwóch tabel, Oznacza to, że kolekcja nie jest zbiorem encji, ale zbiorem prostych typów (ciągi znaków itp. .) lub zbiór elementów do osadzania (klasa z adnotacją @Embeddable ).
Oto przykład do utrwalenia listy String
Oto przykład do utrwalenia listy obiektów niestandardowych
W tym przypadku musimy uczynić klasę Embeddable
źródło
Oto rozwiązanie do przechowywania zestawu przy użyciu @Converter i StringTokenizer. Trochę więcej testów z rozwiązaniem @ jonck-van-der-kogel .
W swojej klasie Entity:
StringSetConverter:
źródło
Moim rozwiązaniem tego problemu było oddzielenie klucza podstawowego od klucza obcego. Jeśli używasz eclipse i dokonałeś powyższych zmian, pamiętaj o odświeżeniu eksploratora bazy danych. Następnie ponownie utwórz jednostki z tabel.
źródło