Kolejna powtórzona kolumna w mapowaniu błędu jednostki


112

Mimo wszystkich innych postów nie mogę znaleźć rozwiązania tego błędu w GlassFish, na MacOSX, NetBeans 7.2.

Here the error :
SEVERE: Exception while invoking class org.glassfish.persistence.jpa.JPADeployer
prepare method
SEVERE: Exception while preparing the app
SEVERE: [PersistenceUnit: supmarket] Unable to build EntityManagerFactory

...

Caused by: org.hibernate.MappingException: Repeated column in mapping for entity:
com.supmarket.entity.Sale column: customerId
(should be mapped with insert="false" update="false")

Tutaj kod:

Sale.java

@Entity
public class Sale {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(nullable=false)
    private Long idFromAgency;

    private float amountSold;

    private String agency;

    @Temporal(javax.persistence.TemporalType.DATE)
    private Date createdate;

    @Column(nullable=false)
    private Long productId;

    @Column(nullable=false)
    private Long customerId;

    @ManyToOne(optional=false)
    @JoinColumn(name="productId",referencedColumnName="id_product")
    private Product product;

    @ManyToOne(optional=false)
    @JoinColumn(name="customerId",referencedColumnName="id_customer")
    private Customer customer;


    public void Sale(){}    
    public void Sale(Long idFromAgency, float amountSold, String agency
            , Date createDate, Long productId, Long customerId){        
        ...
    }

    // then getters/setters
}

Customer.java

@Entity
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="id_customer")
    private Long id_customer;

    @Column(nullable=false)
    private Long idFromAgency;

    private String  gender,
                    maritalState,
                    firstname,
                    lastname,
                    incomeLevel;

    @OneToMany(mappedBy="customer",targetEntity=Sale.class, fetch=FetchType.EAGER)
    private Collection sales;


    public void Customer(){}

    public void Customer(Long idFromAgency, String gender, String maritalState,
            String firstname, String lastname, String incomeLevel) {
        ...
    }

}

Product.java

public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="id_product")
    private Long id_product;

    @Column(nullable=false)
    private Long idFromAgency;

    private String name;

    @OneToMany(mappedBy="product",targetEntity=Sale.class, fetch=FetchType.EAGER)
    private Collection sales;

    //constructors + getters +setters
}

Odpowiedzi:


130

Przesłanie jest jasne: w mapowaniu masz powtórzoną kolumnę. Oznacza to, że dwukrotnie zmapowano tę samą kolumnę bazy danych. I rzeczywiście masz:

@Column(nullable=false)
private Long customerId;

i również:

@ManyToOne(optional=false)
@JoinColumn(name="customerId",referencedColumnName="id_customer")
private Customer customer;

(i to samo dotyczy productId/ product).

Nie należy odwoływać się do innych podmiotów za pomocą ich identyfikatora, ale przez bezpośrednie odniesienie do podmiotu. Usuń customerIdpole, jest bezużyteczne. I zrób to samo dla productId. Jeśli chcesz mieć identyfikator klienta sprzedaży, wystarczy to zrobić:

sale.getCustomer().getId()

1
Otrzymuję ten sam błąd, ale moja sytuacja jest nieco inna. Moja jednostka może być ojcem jednej lub kilku jednostek tego samego typu. Dzieci mają odniesienie do identyfikatora swojego ojca, a także własny unikalny identyfikator. Jak mogę rozwiązać taką cykliczną zależność?
Ciri

@JBNizet Jak więc mogę zapisać sprzedaż z jakimś szczególnym customerId? (np. z JSON).
Michaił Batcer

2
Customer customer = entityManager.getReference(customerId, Customer.class); sale.setCustomer(customer);
JB Nizet

5
Jak poradzisz sobie w przypadku, gdy masz @EmbeddedIdklucz złożony między customerIda innym polem Customerklasy? W takim przypadku potrzebuję obu powtórzonych kolumn w mapowaniu, czy mam rację?
louis amoros

2
@louisamoros Tak, powtarzasz to, ale dodajesz @MapsId("customerId"), patrz stackoverflow.com/questions/16775055/hibernate-embeddedid-join
Dalibor Filus

71

Jeśli utkniesz w starszej bazie danych, w której ktoś już umieścił adnotacje JPA, ale NIE zdefiniował relacji, a teraz próbujesz zdefiniować je do użycia w swoim kodzie, możesz NIE być w stanie usunąć customerId @Column od czasu innego kodu może już bezpośrednio odnosić się do niego. W takim przypadku zdefiniuj relacje w następujący sposób:

@ManyToOne(optional=false)
@JoinColumn(name="productId",referencedColumnName="id_product", insertable=false, updatable=false)
private Product product;

@ManyToOne(optional=false)
@JoinColumn(name="customerId",referencedColumnName="id_customer", insertable=false, updatable=false)
private Customer customer;

Umożliwia to dostęp do relacji. Jednak aby dodać / zaktualizować relacje, będziesz musiał manipulować kluczami obcymi bezpośrednio za pomocą ich zdefiniowanych wartości @Column. To nie jest idealna sytuacja, ale jeśli masz taką sytuację, przynajmniej możesz zdefiniować relacje, aby móc z powodzeniem używać JPQL.


1
Dzięki, to jest dokładnie to rozwiązanie, którego potrzebuję, oprócz ManyToOnepola mapowania potrzebuję pola bezpośrednio zmapowanego na kolumnę złączenia.
ryenus

Jest to właściwe rozwiązanie, gdy masz pole, które jest jednocześnie kluczem obcym i kluczem podstawowym.
AntuanSoft

O mój Boże, mogłeś uratować mi dzień ... dokładnie w tym przypadku
Clomez,

23

użyj tego, to działa dla mnie:

@Column(name = "candidate_id", nullable=false)
private Long candidate_id;
@ManyToOne(optional=false)
@JoinColumn(name = "candidate_id", insertable=false, updatable=false)
private Candidate candidate;

Dzięki, to jest dokładnie to rozwiązanie, którego potrzebuję

Działa nawet z opcjonalnym = true.
Ondřej Stašek

11
@Id
@Column(name = "COLUMN_NAME", nullable = false)
public Long getId() {
    return id;
}

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, targetEntity = SomeCustomEntity.class)
@JoinColumn(name = "COLUMN_NAME", referencedColumnName = "COLUMN_NAME", nullable = false, updatable = false, insertable = false)
@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.ALL)
public List<SomeCustomEntity> getAbschreibareAustattungen() {
    return abschreibareAustattungen;
}

Jeśli już zmapowałeś kolumnę i przypadkowo ustawiłeś te same wartości dla nazwy, a referencedColumnName w hibernacji @JoinColumn daje ten sam głupi błąd

Błąd:

Przyczyna: org.hibernate.MappingException: powtórzona kolumna w mapowaniu dla encji: com.testtest.SomeCustomEntity kolumna: COLUMN_NAME (powinna być zamapowana z insert = "false" update = "false")


2
Kluczową kwestią dla mnie było to, że błąd mówi, że „należy zamapować za pomocą insert = false update = false”, ale rzeczywiste parametry / metody powinny mieć wartość „insertable = false, updatable = false”.
Night Owl

1

Mam nadzieję, że to pomoże!

@OneToOne(optional = false)
    @JoinColumn(name = "department_id", insertable = false, updatable = false)
    @JsonManagedReference
    private Department department;

@JsonIgnore
    public Department getDepartment() {
        return department;
    }

@OneToOne(mappedBy = "department")
private Designation designation;

@JsonIgnore
    public Designation getDesignation() {
        return designation;
    }

0

Uważaj, aby zapewnić tylko 1 ustawiającego i pobierającego dla dowolnego atrybutu. Najlepszym sposobem podejścia jest zapisanie definicji wszystkich atrybutów, a następnie użycie narzędzia ustawiającego i pobierającego generowanie zaćmienia zamiast robienia tego ręcznie. Opcja jest dostępna po kliknięciu prawym przyciskiem myszy -> źródło -> Generuj pobierające i ustawiające.


0

Oznacza to, że dwukrotnie mapujesz kolumnę w swojej klasie encji. Wyjaśnienie na przykładzie ...

    @Column(name = "column1")
    private String object1;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "column1", referencedColumnName = "column1")
    private TableClass object2;

Problem w powyższym fragmencie kodu polega na tym, że powtarzamy mapowanie ...

Rozwiązanie

Ponieważ mapowanie jest ważną częścią, nie chcesz tego usuwać. Zamiast tego usuniesz

    @Column(name = "column1")
    private String uniqueId;

Nadal możesz przekazać wartość object1, tworząc obiekt TableClass i przypisując w nim wartość String obiektu Object1.

Działa to w 100%. Przetestowałem to z bazą danych Postgres i Oracle.


0

Rozwiązaliśmy zależność cykliczną (jednostki nadrzędne-podrzędne), mapując jednostkę podrzędną zamiast jednostki nadrzędnej w Grails 4 (GORM).

Przykład:

Class Person {
    String name
}

Class Employee extends Person{
    String empId
}

//Before my code 
Class Address {
    static belongsTo = [person: Person]
}

//We changed our Address class to:
Class Address {
    static belongsTo = [person: Employee]
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.