Ich bin ziemlich neu zu JPA und Hibernate (ich studiere hart aber!) Und ich kämpfe mit einem Problem, für das ich nicht scheinen kann, eine triviale Lösung zu finden , hier ist es also.Hibernate: Lazy Initialisierung vs gebrochenen Hashcode/Gleichgestellte Rätsel
Ich habe eine Entität, die ein bisschen wie folgt aussieht:
@Entity
@Table(name = "mytable1")
public class EntityOne {
// surrogate key, database generated
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
// business key
@Column(name = "identifier", nullable = false, unique = true)
private String identifier;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
@JoinColumn(name = "twoId", nullable = false)
private EntityTwo two;
@OneToMany(mappedBy = "entityOne", fetch = FetchType.EAGER,
cascade = {CascadeType.ALL}, orphanRemoval = true)
private Set<EntityThree> resources = new HashSet<>();
// getters/setters omitted
@Override
public int hashCode() {
// the business key should always be defined (through constructor/query)
// if this is null the class violates the general hashcode contract
// that the integer value returned must always be the same
Assert.notNull(identifier);
// a dirty alternative would be:
// if(identifier==null) return 0;
return identifier.hashCode();
}
@Override
public boolean equals(Object o) {
return o instanceof ResourceGroup
&& ((ResourceGroup) o).identifier.equals(identifier);
}
}
Mein Projekt ist mit Frühling JPA eingerichtet, so habe ich meine CrudRepository<EntityOne,Long>
in einer Service-Klasse injiziert, die ein paar @Transactional
Methoden hat und ich scannen meine Domain/Service-Pakete für JPA bzw. Transaktionen.
Eine der Servicemethoden ruft die Methode findAll()
des Repositorys auf und gibt eine Liste mit EntityOne
s zurück. Alles funktioniert gut, wenn ich versuche, den Getter für den Zugriff auf für two
, die offensichtlich wirft:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
Ich dachte, es nützlich sein könnte, dieses Objekt initialisiert zu haben, so schaltete ich die Abruf Art von faul zu eifrig. Allerdings, wenn ich, dass ich folgendes erhalten:
java.lang.IllegalArgumentException: [Assertion failed] - this argument is required; it must not be null
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.util.Assert.notNull(Assert.java:123)
at my.pkg.domain.EntityOne.hashCode(ResourceGroup.java:74)
at java.util.HashMap.hash(HashMap.java:351)
at java.util.HashMap.put(HashMap.java:471)
at java.util.HashSet.add(HashSet.java:217)
at java.util.AbstractCollection.addAll(AbstractCollection.java:334)
at org.hibernate.collection.internal.PersistentSet.endRead(PersistentSet.java:346)
at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:243)
at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:233)
at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:209)
at org.hibernate.loader.Loader.endCollectionLoad(Loader.java:1149)
//...
ich kurz sah Hibernate Quellcode und es sieht aus wie es versucht, meine EntityOne
Objekte in einem Satz vor ihr Geschäft Schlüssel initialisiert zu setzen. Ist meine Interpretation richtig? Gibt es einen Weg dahin? Mache ich etwas unglaublich dummes?
Ich schätze Ihre Hilfe
EDIT: Ich will nur, dass zu klären, was ich versuche, hier zu verstehen ist, was die besten Praktiken speziell in Bezug auf PPV und Hibernate. Wenn dies ein einfaches POJO wäre, könnte ich das Identifier-Feld final machen (ich würde die ganze Klasse tatsächlich unveränderlich machen) und sicher sein. Ich kann das nicht, weil ich JPA verwende. Also die Fragen: verletzen Sie den hashCode-Vertrag und auf welche Weise? Wie geht Hibernate mit dieser Verletzung um? Was ist der von der JPA empfohlene Weg, dies generell zu tun? Soll ich Hash-basierte Sammlungen komplett loswerden und stattdessen Listen verwenden?
Giovanni
Ich ersetzte alle meine ursprünglichen 'Set'-Felder mit' new LinkedHashMap() 'anstelle von' new HashMap() 'und es begann zu arbeiten. Ist es nicht seltsam? –