Ich habe eine Personenklasse:
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
@ManyToMany(fetch = FetchType.LAZY)
private List<Role> roles;
// etc
}
Mit einer Viele-zu-Viele-Beziehung ist das faul.
In meinem Controller habe ich
@Controller
@RequestMapping("/person")
public class PersonController {
@Autowired
PersonRepository personRepository;
@RequestMapping("/get")
public @ResponseBody Person getPerson() {
Person person = personRepository.findOne(1L);
return person;
}
}
Und das PersonRepository ist genau dieser Code, der gemäß dieser Anleitung geschrieben wurde
public interface PersonRepository extends JpaRepository<Person, Long> {
}
In diesem Controller benötige ich jedoch tatsächlich die Lazy-Daten. Wie kann ich das Laden auslösen?
Der Versuch, darauf zuzugreifen, schlägt mit fehl
Fehler beim Initialisieren einer Rollensammlung: no.dusken.momus.model.Person.roles, Proxy konnte nicht initialisiert werden - keine Sitzung
oder andere Ausnahmen, je nachdem, was ich versuche.
Meine XML-Beschreibung , falls benötigt.
Vielen Dank.
Person
Objekt mit einem bestimmten Parameter abzurufen ? DarinQuery
enthalten diefetch
Klausel und laden dieRoles
auch für die Person.Antworten:
Sie müssen die Lazy-Sammlung explizit aufrufen, um sie zu initialisieren (es ist üblich, zu
.size()
diesem Zweck aufzurufen ). Im Ruhezustand gibt es eine dedizierte Methode für this (Hibernate.initialize()
), aber JPA hat kein Äquivalent dazu. Natürlich müssen Sie sicherstellen, dass der Aufruf erfolgt, wenn die Sitzung noch verfügbar ist. Kommentieren Sie daher Ihre Controller-Methode mit@Transactional
. Eine Alternative besteht darin, eine Zwischen-Service-Schicht zwischen dem Controller und dem Repository zu erstellen, die Methoden verfügbar machen kann, die verzögerte Sammlungen initialisieren.Aktualisieren:
Bitte beachten Sie, dass die obige Lösung einfach ist, jedoch zu zwei unterschiedlichen Abfragen an die Datenbank führt (eine für den Benutzer, eine andere für seine Rollen). Wenn Sie eine bessere Leistung erzielen möchten, fügen Sie Ihrer Spring Data JPA-Repository-Schnittstelle die folgende Methode hinzu:
Diese Methode verwendet die Fetch-Join- Klausel von JPQL, um die Rollenzuordnung in einem einzigen Roundtrip in die Datenbank eifrig zu laden, und verringert daher die Leistungseinbußen, die durch die beiden unterschiedlichen Abfragen in der obigen Lösung entstehen.
quelle
join
ohne diefetch
, wird das Set mit zurückgegebeninitialized = false
; Daher wird nach dem Zugriff auf die Gruppe immer noch eine zweite Abfrage ausgegeben.fetch
Dies ist der Schlüssel, um sicherzustellen, dass die Beziehung vollständig geladen ist, und um die zweite Abfrage zu vermeiden.Obwohl dies ein alter Beitrag ist, sollten Sie @NamedEntityGraph (Javax Persistence) und @EntityGraph (Spring Data JPA) verwenden. Die Kombination funktioniert.
Beispiel
und dann das Feder-Repo wie unten
quelle
@NamedEntityGraph
Teil der JPA 2.1-API ist, die vor der Version 4.3.0 nicht in Hibernate implementiert wurde.@EntityGraph(attributePaths = "employeeGroups")
kann direkt in einem Spring Data Repository verwendet werden, um eine Methode zu kommentieren, ohne dass ein@NamedEntityGraph
Code auf Ihrem @Entity-freien Code erforderlich ist, der beim Öffnen des Repos leicht zu verstehen ist.Sie haben einige Möglichkeiten
Mehr Arbeit, beste Leistung.
Weniger Arbeit, normalerweise in Webumgebungen akzeptabel.
Weniger Arbeit, nützlich, wenn OEMIV nicht verfügbar ist, z. B. in einer Swing-Anwendung, aber auch bei Repository-Implementierungen, um eine Entität auf einmal zu initialisieren.
Für die letzte Option habe ich eine Utility-Klasse geschrieben, JpaUtils , um Entitäten bei einem Deph zu initialisieren.
Beispielsweise:
quelle
Es kann nur während einer Transaktion träge geladen werden. Sie können also auf die Sammlung in Ihrem Repository zugreifen, die eine Transaktion enthält - oder was ich normalerweise mache, ist ein
get with association
oder den Fetch-Modus auf eifrig setzen.quelle
Ich denke, Sie benötigen OpenSessionInViewFilter , um Ihre Sitzung während des Renderns der Ansicht offen zu halten (dies ist jedoch keine allzu gute Vorgehensweise).
quelle
Federdaten
JpaRepository
Die Federdaten
JpaRepository
definieren die folgenden zwei Methoden:getOne
, der einen Entitäts-Proxy zurückgibt, der zum Festlegen einer@ManyToOne
oder einer@OneToOne
übergeordneten Zuordnung geeignet ist, wenn eine untergeordnete Entität beibehalten wird .findById
, der die Entität POJO zurückgibt, nachdem die SELECT-Anweisung ausgeführt wurde, die die Entität aus der zugehörigen Tabelle lädtIn Ihrem Fall haben Sie jedoch weder angerufen
getOne
nochfindById
:Ich gehe also davon aus, dass die
findOne
Methode eine Methode ist, die Sie in der definiert habenPersonRepository
. DiefindOne
Methode ist in Ihrem Fall jedoch nicht sehr nützlich. Da Sie die SammlungPerson
zusammen mit isroles
abrufen müssen, ist es besser,findOneWithRoles
stattdessen eine Methode zu verwenden.Benutzerdefinierte Spring Data-Methoden
Sie können eine
PersonRepositoryCustom
Schnittstelle wie folgt definieren:Und definieren Sie die Implementierung folgendermaßen:
Das ist es!
quelle
Sie können dasselbe wie folgt tun:
Verwenden Sie einfach faqQuestions.getFaqAnswers (). Size () in Ihrem Controller, und Sie erhalten die Größe, wenn Sie die Liste träge initialisiert haben, ohne die Liste selbst abzurufen.
quelle