2013-02-17 14 views
5

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 
+1

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. –

+0

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]. –

+0

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. –

Odpowiedz

2

usunąć kaskadę = {CascadeType.REFRESH, CascadeType.MERGE, CascadeType.PERSIST} z podmiotem płatności.

Ponieważ PaymentMethod jest tabelą wzorcową, tak jak powiedziałeś, nie chcesz wykonywać żadnych operacji kaskadowych od Payment do PaymentMethod.

+0

Jeśli usunę go, oznacza, że ​​odłączony podmiot próbuje zapisać .. –

+0

potrzebujesz pobrać instancję obiektu PaymentMethod i przypisać ją do obiektu płatności. – spiritwalker

+0

W tej sytuacji robię to samo –

3

Zacznij od usunięcia kaskad, ponieważ nie chcesz tworzyć/modyfikować PaymentMethod podczas tworzenia/modyfikowania płatności.

Następnie podczas tworzenia płatności, przypisać go istniejąca PAYMENTMETHOD chcesz to być związane z:

PaymentMethod existingPaymentMethod = em.find(PaymentMethod.class, idOfThePaymentMethod); 
Payment payment = new Payment(); 
payment.setPaymentMethod(existingPaymentMethod); 
em.persist(payment); 
+0

repozytorium sprężyn daje metodę składowania, która wewnętrznie robi to samo, jeśli id ​​ma wartość null –

+0

Jeśli id ​​tego, co jest zerowe? Wiosenne repozytorium zabiera przedmioty, które mu dajesz. Jeśli dasz mu nowy PaymentMethod zamiast dawać mu istniejący, to nie będzie działać tak, jak chcesz. –

+0

Poprawiono, ale po ustawieniu prawidłowego obiektu nadal działa w ten sam sposób. Nie można ustalić, dlaczego? –

Powiązane problemy