Un'altra colonna ripetuta nella mappatura per errore di entità


110

Nonostante tutti gli altri post, non riesco a trovare una soluzione per questo errore con GlassFish, su 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")

Qui il codice:

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
}

Risposte:


129

Il messaggio è chiaro: hai una colonna ripetuta nella mappatura. Ciò significa che hai mappato due volte la stessa colonna del database. E in effetti, hai:

@Column(nullable=false)
private Long customerId;

e anche:

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

(e lo stesso vale per productId/ product).

Non dovresti fare riferimento ad altre entità tramite il loro ID, ma tramite un riferimento diretto all'entità. Togli il customerIdcampo, è inutile. E fai lo stesso per productId. Se vuoi l'ID cliente di una vendita, devi solo fare questo:

sale.getCustomer().getId()

1
Ricevo lo stesso errore, ma la mia situazione è leggermente diversa. La mia entità può essere il padre di una o più entità dello stesso tipo. I bambini hanno un riferimento sull'ID del padre e un ID univoco. Come posso risolvere una dipendenza così circolare?
Ciri

@JBNizet Come posso salvare una vendita con qualche particolare customerId? (ad esempio da JSON).
Mikhail Batcer

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

5
Come gestisci il caso in cui hai una @EmbeddedIdchiave composta tra customerIde un altro campo della Customerclasse? In questo caso ho bisogno di entrambe le colonne ripetute nella mappatura, giusto?
louis amoros

2
@louisamoros Sì, lo ripeti, ma aggiungi @MapsId("customerId"), vedi stackoverflow.com/questions/16775055/hibernate-embeddedid-join
Dalibor Filus

71

Se sei bloccato con un database legacy in cui qualcuno ha già inserito annotazioni JPA ma NON ha definito le relazioni e ora stai cercando di definirle per l'uso nel tuo codice, potresti NON essere in grado di eliminare il customerId @Column a partire da altro codice può già farvi riferimento direttamente. In tal caso, definire le relazioni come segue:

@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;

Questo ti permette di accedere alle relazioni. Tuttavia, per aggiungere / aggiornare le relazioni dovrai manipolare le chiavi esterne direttamente tramite i loro valori @Column definiti. Non è una situazione ideale, ma se ti viene consegnato questo tipo di situazione, almeno puoi definire le relazioni in modo da poter utilizzare JPQL con successo.


1
Grazie, questa è esattamente la soluzione di cui ho bisogno, oltre al ManyToOnecampo di mappatura, ho bisogno di un campo mappato direttamente alla colonna di join.
ryenus

Questa è la soluzione giusta quando hai un campo che è chiave esterna e chiave primaria allo stesso tempo.
AntuanSoft

Oh mio Dio, potresti
avermi

22

usa questo, è lavoro per me:

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

Grazie, questa è esattamente la soluzione di cui ho bisogno

Funziona anche con optional = 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;
}

Se hai già mappato una colonna e hai accidentalmente impostato gli stessi valori per name e referencedColumnName in @JoinColumn hibernate dà lo stesso stupido errore

Errore:

Causato da: org.hibernate.MappingException: colonna ripetuta nella mappatura per l'entità: com.testtest.SomeCustomEntity colonna: COLUMN_NAME (dovrebbe essere mappata con insert = "false" update = "false")


2
Un punto chiave qui per me era che l'errore dice "dovrebbe essere mappato con insert = false update = false" ma i parametri / metodi effettivi dovrebbero essere "insertable = false, updatable = false".
Night Owl

1

Spero che questo ti aiuti!

@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

Assicurati di fornire solo 1 setter e getter per ogni attributo. Il modo migliore per avvicinarsi è scrivere la definizione di tutti gli attributi, quindi utilizzare eclipse generate setter e getter utility piuttosto che farlo manualmente. L'opzione viene visualizzata facendo clic con il pulsante destro del mouse-> sorgente -> Genera Getter e Setter.


0

Ciò significa che stai mappando una colonna due volte nella tua classe di entità. Spiegando con un esempio ...

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

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

Il problema nello snippet di codice sopra è che stiamo ripetendo la mappatura ...

Soluzione

Poiché la mappatura è una parte importante, non vuoi rimuoverla. Invece, rimuoverai

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

È comunque possibile passare il valore di object1 creando un oggetto di TableClass e assegnare il valore String di Object1 in esso.

Funziona al 100%. L'ho testato con Postgres e il database Oracle.


0

Abbiamo risolto la dipendenza circolare (entità padre-figlio) mappando l'entità figlia invece dell'entità padre in Grails 4 (GORM).

Esempio:

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]
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.