ошибка обновления JPA Entity - PullRequest
5 голосов
/ 24 июня 2011

У меня есть следующая модель домена

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

или по-английски

Товар имеет одну или несколько цен. Каждая цена выражена в определенной валюте.

Price имеет составной первичный ключ (обозначается PricePK ниже), который состоит из внешних ключей для Currency и Product. Ниже приведены соответствующие разделы Java-аннотированных классов JPA (в основном, методы получения и установки отсутствуют):

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

Когда я пытаюсь обновить экземпляр Product, я получаю StackOverflowError, поэтому я подозреваю, что в отображении выше есть какой-то цикл (или другая ошибка), может кто-нибудь его обнаружить?

Ответы [ 3 ]

2 голосов
/ 24 июня 2011

Я видел эту ошибку несколько раз, но не могу вспомнить точное решение. У меня есть идея, что вам нужно удалить сопоставление из PricePK (оба @ManyToOne) и заменить его на @AssociationOverrides on 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 {
    [...]
}

пожалуйста, убедитесь, что имена столбцов в порядке, так как я не вижу столбцы идентификаторов в Product или Currency.

1 голос
/ 04 января 2012

Я столкнулся с подобной проблемой, и она оказалась вызванной CascadeType.ALL, определенной в аннотации OneToMany. Когда вы обновляете продукт, он пытается обновить цены в постоянном контексте.

В зависимости от ситуации вы можете обойтись без обновления цен при обновлении продукта в менеджере организации, например:

@OneToMany(mappedBy = "pricePK.product", cascade = {
        CascadeType.PERSIST, CascadeType.MERGE
    }, orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
private Collection<Price> defaultPrices = new ArrayList<Price>();
0 голосов
/ 30 июня 2011

Разве вы не должны просто объявить отношения между ценой к товару и валютой как ManyToOne непосредственно в сущности Price и аннотировать Price с помощью @IdClass (PricePK)?

Я не знаю, как Hibernate справляется с этимхотя, но я успешно реализовал это с помощью OpenJPA.В этом случае PricePK должен объявить свои поля с теми же именами, что и в Price, но вместо этого использовать простой тип (Integer вместо Currency или Product).В Price может потребоваться аннотировать товар и валюту с помощью @Id.Обратите внимание, что это не соответствует спецификации JPA (@IdClass поддерживает только простые поля).

...