2011-06-24 10 views
5

tengo el siguiente modelo de dominioerror refrescante APP Entidad

Currency ----<Price>---- Product 

O en Inglés

A Product has one or more Prices. Each Price is denominated in a particular Currency.

Price tiene una clave principal compuesta (representar por PricePK abajo) que se compone de las claves ajenas a Currency y Product. Las secciones pertinentes de las clases Java anotadas-APP están por debajo (captadores y definidores mayoría omitidas):

@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 
public class Currency { 

    @Id 
    private Integer ix; 

    @Column 
    private String name; 

    @OneToMany(mappedBy = "pricePK.currency", cascade = CascadeType.ALL, orphanRemoval = true) 
    @LazyCollection(LazyCollectionOption.FALSE) 
    private Collection<Price> prices = new ArrayList<Price>(); 
} 

@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 
public class Product { 

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private Integer id; 

    @OneToMany(mappedBy = "pricePK.product", cascade = CascadeType.ALL, orphanRemoval = true) 
    @LazyCollection(LazyCollectionOption.FALSE) 
    private Collection<Price> defaultPrices = new ArrayList<Price>(); 
} 

@Embeddable 
public class PricePK implements Serializable { 

    private Product product;  
    private Currency currency; 

    @ManyToOne(optional = false) 
    public Product getProduct() { 
     return product; 
    } 

    @ManyToOne(optional = false) 
    public Currency getCurrency() { 
     return currency; 
    }  
} 

@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 
public class Price { 

    private PricePK pricePK = new PricePK(); 

    private BigDecimal amount; 

    @Column(nullable = false) 
    public BigDecimal getAmount() {  
     return amount; 
    } 

    public void setAmount(BigDecimal amount) {  
     this.amount = amount; 
    } 

    @EmbeddedId 
    public PricePK getPricePK() { 
     return pricePK; 
    }  

    @Transient 
    public Product getProduct() { 
     return pricePK.getProduct(); 
    } 

    public void setProduct(Product product) { 
     pricePK.setProduct(product); 
    } 

    @Transient 
    public Currency getCurrency() { 
     return pricePK.getCurrency(); 
    } 

    public void setCurrency(Currency currency) { 
     pricePK.setCurrency(currency); 
    } 
} 

Cuando intento refresh una instancia de Product, aparece un StackOverflowError, por lo que sospechan que hay algún tipo de ciclo (u otro error) en el mapeo anterior, ¿alguien puede detectarlo?

+0

+1, muy bien plantea la pregunta. Tengo curiosidad acerca del modelo de dominio, sin embargo. Parece extraño que un 'Precio' se identifique de forma única por' Producto' + 'Moneda' en lugar de, digamos, su valor (escalar) +' Moneda'. –

+0

Gracias Matt, en realidad hay un campo 'cantidad BigDecimal' en la clase' Price' también, pero lo omití aquí porque no es relevante para la pregunta, y quería mantener la lista del código lo más corta posible –

Respuesta

2

He visto este error varias veces, pero no recuerdo la solución exacta. Tengo la idea de que debes eliminar el mapeo de PricePK (ambos @ManyToOne) y reemplazarlo con @AssociationOverrides en Price.

@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 
@AssociationOverrides({ 
    @AssociationOverride(name = "pricePK.product", 
         joinColumns = @JoinColumn(name = "product_id")), 
    @AssociationOverride(name = "pricePK.currency", 
         joinColumns = @JoinColumn(name = "currency_id")) 
}) 
public class Price extends VersionedEntity { 
    [...] 
} 

por favor, compruebe que los nombres de las columnas estén bien, ya que no puedo ver las columnas de identificación en Producto o Moneda.

+0

Tengo actualizó las clases para mostrar las columnas de ID –

+0

@Don ¿Ha probado esta solución? Además, no me expresé correctamente, los * nombres de columna * que mencioné son los nombres de las columnas en Price. Así que asumí que en la tabla de precios tiene dos columnas llamadas ** product_id ** y ** currency_id. ** – Augusto

+0

Intenté su sugerencia, pero causó este error: 'No se pudo determinar el tipo para: com.example.Currency, en la tabla: PRECIO, para columnas: [org.hibernate.mapping.Column (currency)] ' –

0

¿No debería declarar las relaciones entre Precio y Producto y Moneda como ManyToOne directamente en la entidad Precio y anotar Precio con @IdClass (PricePK)?

No sé cómo Hibernate maneja esto, pero lo he implementado con éxito usando OpenJPA. En ese caso, PricePK debe declarar sus campos con los mismos nombres que en Price, pero usando el tipo simple en su lugar (Integer en lugar de Currency o Product). En Price, es posible que deba anotar el producto y la moneda con @Id. Tenga en cuenta que esto está fuera de la especificación JPA (@IdClass solo admite campos simples).

1

Me encontré con un problema similar y resultó ser causado por el CascadeType.ALL definido en la anotación de OneToMany. Cuando actualice el producto, intentará actualizar los precios que están en el contexto persistente.

Dependiendo de la situación, es posible que pueda salir adelante sin tener los precios actualizan cuando el producto se actualiza en el gestor de la entidad, tales como:

@OneToMany(mappedBy = "pricePK.product", cascade = { 
     CascadeType.PERSIST, CascadeType.MERGE 
    }, orphanRemoval = true) 
@LazyCollection(LazyCollectionOption.FALSE) 
private Collection<Price> defaultPrices = new ArrayList<Price>(); 
Cuestiones relacionadas