Outra coluna repetida no mapeamento para erro de entidade

110

Apesar de todas as outras postagens, não consigo encontrar uma solução para este erro com GlassFish, no 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")

Aqui está o código:

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
}
canardman
fonte

Respostas:

129

A mensagem é clara: você tem uma coluna repetida no mapeamento. Isso significa que você mapeou a mesma coluna do banco de dados duas vezes. E, de fato, você tem:

@Column(nullable=false)
private Long customerId;

e também:

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

(e o mesmo vale para productId/product ).

Você não deve fazer referência a outras entidades por seu ID, mas por uma referência direta à entidade. Remova o customerIdcampo, é inútil. E faça o mesmo por productId. Se você deseja o ID do cliente de uma venda, você só precisa fazer o seguinte:

sale.getCustomer().getId()
JB Nizet
fonte
1
Recebo o mesmo erro, mas minha situação é um pouco diferente. Minha entidade pode ser o pai de uma ou mais entidades do mesmo tipo. Os filhos têm uma referência sobre o id do pai, bem como um id exclusivo para eles. Como posso resolver essa dependência circular?
Ciri
@JBNizet Como então posso salvar uma venda com algum particular customerId? (por exemplo, de JSON).
Mikhail Batcer
2
Customer customer = entityManager.getReference(customerId, Customer.class); sale.setCustomer(customer);
JB Nizet
5
Como você lida com o caso em que há uma @EmbeddedIdchave composta entre customerIde outro campo doCustomer classe? Nesse caso, preciso de ambas as colunas repetidas no mapeamento, certo?
louis amoros
2
@louisamoros Sim, você repete, mas adiciona @MapsId("customerId"), consulte stackoverflow.com/questions/16775055/hibernate-embeddedid-join
Dalibor Filus
71

Se você está preso a um banco de dados legado onde alguém já colocou anotações JPA, mas NÃO definiu os relacionamentos e agora está tentando defini-los para uso em seu código, então você NÃO poderá excluir o customerId @Column porque outro código já pode referenciá-lo diretamente. Nesse caso, defina as relações da seguinte forma:

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

Isso permite que você acesse os relacionamentos. No entanto, para adicionar / atualizar os relacionamentos, você terá que manipular as chaves estrangeiras diretamente por meio de seus valores @Column definidos. Não é uma situação ideal, mas se você tiver esse tipo de situação, pelo menos poderá definir os relacionamentos para que possa usar JPQL com sucesso.

Pattmatt
fonte
1
Obrigado, esta é exatamente a solução que preciso, além do ManyToOnecampo de mapeamento, preciso de um campo mapeado diretamente para a coluna de junção.
ryenus
Esta é a solução certa quando você tem um campo que é chave estrangeira e chave primária ao mesmo tempo.
AntuanSoft
Oh meu Deus, você pode ter salvado meu dia ... exatamente este caso
Clomez
22

use isso, é trabalho para mim:

@Column(name = "candidate_id", nullable=false)
private Long candidate_id;
@ManyToOne(optional=false)
@JoinColumn(name = "candidate_id", insertable=false, updatable=false)
private Candidate candidate;
Nômade redouane
fonte
Obrigado, esta é exatamente a solução de que preciso
Funciona mesmo com 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 você já mapeou uma coluna e acidentalmente definiu os mesmos valores para name e referencedColumnName em @JoinColumn hibernate dá o mesmo erro estúpido

Erro:

Causado por: org.hibernate.MappingException: Coluna repetida no mapeamento para a entidade: com.testtest.SomeCustomEntity coluna: COLUMN_NAME (deve ser mapeado com insert = "false" update = "false")

dbow
fonte
2
Um ponto-chave aqui para mim foi que o erro diz "deve ser mapeado com insert = false update = false", mas os parâmetros / métodos reais devem ser "insertable = false, updatable = false".
Night Owl de
1

Espero que isso ajude!

@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;
    }
Multi Cabz
fonte
0

Tenha o cuidado de fornecer apenas 1 setter e getter para qualquer atributo. A melhor maneira de abordar é escrever a definição de todos os atributos e, em seguida, usar o eclipse generate setter e o utilitário getter em vez de fazer isso manualmente. A opção vem com o botão direito -> fonte -> Gerar Getter e Setter.

Romil Gaurav
fonte
0

Isso significa que você está mapeando uma coluna duas vezes em sua classe de entidade. Explicando com um exemplo ...

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

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

O problema no snippet de código acima é que estamos repetindo o mapeamento ...

Solução

Como o mapeamento é uma parte importante, você não quer removê-lo. Em vez disso, você removerá

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

Você ainda pode passar o valor de object1 criando um objeto de TableClass e atribuir o valor String de Object1 a ele.

Isso funciona 100%. Eu testei isso com Postgres e banco de dados Oracle.

Rishabh Agarwal
fonte
0

Resolvemos a dependência circular (Entidades pai-filho) mapeando a entidade filha em vez da entidade pai em Grails 4 (GORM).

Exemplo:

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]
}
Vinitha Pukazh Bagya R
fonte