Mam podmiot klasy Płatność która ma klasę Entity PAYMENTMETHOD z wiele do jednego związek.@ManyToOne jednokierunkowy mapowanie
Teraz, ponieważ My PaymentMethod to stół główny.
Więc chcę zapisać płatność bez wpływania na tabelę główną PaymentMethod.
Ale za każdym razem, gdy zapiszę płatność, wstaw nowy wiersz w PaymentMethod do. Nie potrafię zrozumieć dlaczego.
Używam zapisywania SpringData.
Payment.java
@Entity
@Table(name="payment")
public class Payment implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne(cascade={CascadeType.REFRESH,CascadeType.MERGE,CascadeType.PERSIST})
@JoinColumn(name="payment_method_id")
private PaymentMethod paymentMethod;
//getter and setters
}
PaymentMethod.java
@Table(name="paymentmethod")
public class PaymentMethod implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name="name",unique=true ,nullable=false)
private String name;
//GETTER AND SETTERS
}
PAYMENT_METHOD DANE
ID | NAME
1 | AA
2 | BB
3 | CC
Po dokonaniu płatności, zapisz się na wpis PAYMENT_METHOD z duplikatem nazwy?
Nie mogę zrozumieć, dlaczego?
Do zapisywania Stworzyłem prostą CRUDRepository dla płatności typu
wywołującego Zapisz podmiotu repozytorium.
Proszę zasugerować, gdzie wypadam.
ilekroć kod wykonuje tę linię:
paymentMethodRepository.findByName(payment.getPaymentMethod().getName());
To daje błąd jak
Caused by: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing: com.enrollment.domain.Payment.paymentMethod -> com.enrollment.domain.PaymentMethod
at org.hibernate.engine.spi.CascadingAction$8.noCascade(CascadingAction.java:380)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:176)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:423)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:264)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:136)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:78)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151)
at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:870)
at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:863)
at org.hibernate.engine.spi.CascadingAction$8.cascade(CascadingAction.java:346)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:409)
at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:350)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:326)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:448)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:293)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:136)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:78)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151)
at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:870)
at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:863)
at org.hibernate.engine.spi.CascadingAction$8.cascade(CascadingAction.java:346)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:448)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:293)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:136)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:78)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151)
at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:870)
at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:863)
at org.hibernate.engine.spi.CascadingAction$8.cascade(CascadingAction.java:346)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:423)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:264)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:136)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:78)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151)
at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:870)
at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:863)
at org.hibernate.engine.spi.CascadingAction$8.cascade(CascadingAction.java:346)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:423)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:264)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:136)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:78)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:208)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:151)
at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:870)
at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:863)
at org.hibernate.engine.spi.CascadingAction$8.cascade(CascadingAction.java:346)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:409)
at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:350)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:326)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:160)
at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:151)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58)
at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1186)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1241)
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:285)
jestem w stanie dowiedzieć się, jak kod jeśli próbuje opróżnić go, gdy zgłoszę metodę wyszukiwania z repozytorium.
Czy czegoś mi brakuje?
Problem rozwiązany dzięki @JB i @spiritwalker, ale nie można znaleźć dokładnej przyczyny źródłowej, więc po prostu dyskusja na temat zachowania może być dyskusja będzie dodawać zbyt knowledege.
Behaviour ..
Open Transaction
1. validate
2. save child
3. validate and update
4. save parent
Close Transaction
it was giving above error.
Now, after code change it worked
Open Transaction
1. validate
2. validate and update
3. save child
4. save parent
Close Transaction
Problem polega na tym, że w kroku 3, jesteś wykonywania zapytania do bazy danych. Tak więc, przed jego wykonaniem, Hibernate opróżnia zmiany w pamięci, aby upewnić się, że zapytanie może zobaczyć nowe wartości przechowywane w pamięci, ale nie przechowywane jeszcze w bazie danych. A ponieważ stan w pamięci jest nieprawidłowy, otrzymujesz ten wyjątek. –
Prawidłowo, ale ponieważ wciąż jestem w transakcji (readonly = false), więc nie sądzisz, że po wykonaniu kwerendy wyboru, flush nie powinno się zdarzyć. [uwaga: wybór został wykonany dla danych podstawowych]. –
Nie, nie sądzę. Załóżmy, że w transakcji tworzysz wiele płatności, a później w tej samej transakcji chcesz wyświetlić listę wszystkich płatności danego typu. Zdecydowanie chcesz, aby nowo utworzone płatności zostały uwzględnione w wyniku (tak samo, jak w przypadku dodania płatności za pomocą JDBC). Dlatego sesja jest spłukana. –