Jestem całkiem nowy w JPA i Hibernate (ja się intensywnie uczę!) I zmagam się z problemem, który nie wydaje mi się znaleźć trywialne rozwiązanie dla , więc oto jest.Hibernate: Lazy inicjalizacja vs złamany hashcode/równa się zagadka
Mam podmiot, który wygląda trochę jak następuje:
@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);
}
}
Mój projekt jest skonfigurowany z wiosennej WZP, więc mam swoje CrudRepository<EntityOne,Long>
wstrzykiwany w klasie usług, który ma kilka @Transactional
metod i skanować moje pakiety domen/usług odpowiednio dla JPA i transakcji.
Jedna z metod serwisowych wywołuje metodę repozytorium findAll()
i zwraca listę EntityOne
s. Wszystko działa poprawnie, chyba że próby uzyskania dostępu do getter dla two
, co oczywiście rzuca:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
Pomyślałem, że może to być przydatne, że obiekt ten zainicjowany, więc przeszedłem do pobierania typ od leniwy chętny. Jednakże, jeśli to zrobić uzyskać następujące:
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)
//...
krótko spojrzał na kodzie źródłowym Hibernate i wygląda na to, że próbuje umieścić moje EntityOne
obiektów w zestawie przed ich kluczowy obiekt jest inicjowany. Czy moja interpretacja jest poprawna? Czy istnieje sposób obejścia tego? Czy robię coś niesamowicie głupiego?
Doceniam twoją pomoc
EDIT: Chcę tylko wyjaśnić, że to, co usiłuję zrozumieć, oto co najlepsze praktyki są specjalnie względem JPA i Hibernate. Gdyby to było zwykłe POJO, mogłem uczynić pole identyfikatora ostatecznym (uczyniłbym całą klasę niezmienną) i byłoby bezpieczne. Nie mogę tego zrobić, ponieważ używam JPA. Tak więc pytania: czy naruszasz umowę hashCode i w jaki sposób? W jaki sposób Hibernate radzi sobie z tym naruszeniem? Jaki jest ogólnie zalecany sposób WZP? Czy powinienem całkowicie pozbyć się kolekcji hashowych i zamiast tego użyć list?
Giovanni
Wymieniłem wszystkie moje relacyjne wartości początkowe 'Set' fields 'z' new LinkedHashMap()' zamiast 'new HashMap()' i zaczęło działać. Czy to nie dziwne? –