JPA @MapsId вставляет 0 вместо правильного значения

#java #hibernate #jpa

#java #спящий режим #jpa

Вопрос:

У меня есть эти объекты (ненужные столбцы удалены для краткости)

Порядок

 @Entity
@Table(name = "orders")
public class Order {

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

    @OneToOne(mappedBy = "order", cascade = CascadeType.ALL, optional = false)
    private Shipment shipment;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Shipment getShipment() {
        return shipment;
    }

    public void setShipment(Shipment shipment) {
        this.shipment = shipment;
        this.shipment.setOrder(this);
    }
}
 

Пересылка

 @Entity
@Table(name = "shipments")
public class Shipment {

    @Id
    @Column(name = "order_id")
    private int id;

    @OneToOne
    @MapsId
    private Order order;

    @OneToOne(mappedBy = "shipment", cascade = CascadeType.ALL, optional = false)
    private ShippingAddress shippingAddress;

    public Order getOrder() {
        return order;
    }

    public void setOrder(Order order) {
        this.order = order;
    }

    public ShippingAddress getShippingAddress() {
        return shippingAddress;
    }

    public void setShippingAddress(ShippingAddress shippingAddress) {
        this.shippingAddress = shippingAddress;
        this.shippingAddress.setShipment(this);
    }
}
 

Адрес доставки

 @Entity
@Table(name = "shipping_address")
public class ShippingAddress {

    @Id
    @Column(name = "shipment_id")
    private int id;

    @OneToOne
    @MapsId("shipment_id")
    private Shipment shipment;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Shipment getShipment() {
        return shipment;
    }

    public void setShipment(Shipment shipment) {
        this.shipment = shipment;
    }
}
 

Проблема возникает, когда я пытаюсь сохранить новое Order . Как вы можете видеть из журналов, Hibernate правильно устанавливает значения для объектов Order and Shipment , но присваивает 0 shipment_id столбцу in shipping_address , что, конечно, вызывает конфликт FK .

Я считаю, что использую @MapsId правильно, потому что, как я уже сказал, это работает для Order Shipment отношений and , но, похоже, не работает для Shipment and ShippingAddress .

Это журналы

 2021-01-14 14:25:56,563 DEBUG [http-nio-8080-exec-3] org.hibernate.SQL: insert into orders (branch_office, coupon_code, customer_id, external_id, increment_id, interests, origin_channel, store_id, subtotal, total, total_discount, total_qty_ordered) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2021-01-14 14:25:56,564 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [1] as [VARCHAR] - [null]
2021-01-14 14:25:56,564 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [2] as [VARCHAR] - [null]
2021-01-14 14:25:56,564 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [3] as [INTEGER] - [20]
2021-01-14 14:25:56,564 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [4] as [VARCHAR] - [5501505642]
2021-01-14 14:25:56,564 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [5] as [VARCHAR] - [5501505642]
2021-01-14 14:25:56,564 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [6] as [NUMERIC] - [0.0000]
2021-01-14 14:25:56,565 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [7] as [VARCHAR] - [store]
2021-01-14 14:25:56,565 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [8] as [INTEGER] - [55]
2021-01-14 14:25:56,565 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [9] as [NUMERIC] - [2270.0000]
2021-01-14 14:25:56,565 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [10] as [NUMERIC] - [1580]
2021-01-14 14:25:56,565 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [11] as [NUMERIC] - [690]
2021-01-14 14:25:56,565 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [12] as [INTEGER] - [3]

2021-01-14 14:25:56,621 DEBUG [http-nio-8080-exec-3] org.hibernate.SQL: insert into shipments (carrier_id, pickup_id, shipment_id, shipping_cost, order_id) values (?, ?, ?, ?, ?)
2021-01-14 14:25:56,621 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [1] as [INTEGER] - [19]
2021-01-14 14:25:56,622 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [2] as [INTEGER] - [19]
2021-01-14 14:25:56,622 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [3] as [INTEGER] - [null]
2021-01-14 14:25:56,622 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [4] as [NUMERIC] - [0.0]
2021-01-14 14:25:56,622 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [5] as [INTEGER] - [20]

2021-01-14 14:25:56,623 DEBUG [http-nio-8080-exec-3] org.hibernate.SQL: insert into shipping_address (city, country_code, province_id, street_name, street_number, zip_code, shipment_id) values (?, ?, ?, ?, ?, ?, ?)
2021-01-14 14:25:56,624 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [1] as [VARCHAR] - [Vicente López]
2021-01-14 14:25:56,624 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [2] as [VARCHAR] - [AR]
2021-01-14 14:25:56,624 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [3] as [INTEGER] - [21]
2021-01-14 14:25:56,624 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [4] as [VARCHAR] - [ramon melgar,Nro 8170]
2021-01-14 14:25:56,624 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [5] as [VARCHAR] - []
2021-01-14 14:25:56,624 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [6] as [VARCHAR] - [1638]
2021-01-14 14:25:56,624 TRACE [http-nio-8080-exec-3] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [7] as [INTEGER] - [0]
 

Как вы можете видеть на последней вставке, Hibernate пытается вставить 0 вместо shipment_id .

Я чего-то не понимаю?

Комментарии:

1. Вы никогда не должны использовать примитивные (ненулевые) типы для @Id . Переключите его Integer и посмотрите, исправит ли это.

2. @chrylis-осторожно оптимистично — С точки зрения корректности, почему я не должен использовать примитивы для @Id ?

3. Поскольку примитив не способен содержать значение null to , явно означающее «неназначенный», и может возникнуть путаница, если существует реальный идентификатор 0.

4. Вы поднимаете хороший вопрос. Я обновлю свои объекты, чтобы отразить это. Спасибо.

Ответ №1:

Согласно документации, значение @MapsId аннотации относится к имени атрибута в составном ключе, которому соответствует атрибут отношения. Вы не используете составной ключ.

Итак, это:

 @OneToOne
@MapsId("shipment_id")
private Shipment shipment;
 

следует исправить это:

 @OneToOne
@MapsId
@JoinColumn(name = "shipment_id")
private Shipment shipment;
 

Я не могу найти доказательства в документации, но спящий режим игнорируется @Column(name = "shipment_id") @Id при использовании @MapsId , поэтому вы должны указать имя столбца PK ShippingAddress путем добавления @JoinColumn .

Комментарии:

1. Проблема с этим подходом заключается в том, что Hibernate генерирует неправильное имя столбца. Он генерируется order_shipment_id , когда это должно быть shipment_id . Я исправил это, добавив @JoinColumn(name = "shipment_id", referencedColumnName = "order_id") в @MapsId in ShippingAddress , и это работает. Это правильно?

2. Да, это правильно. Я не могу найти доказательства в документации. Но я столкнулся с этим позже. Спящий режим игнорируется @Column(name = "shipment_id") @Id при использовании @MapsId .

3. Вы можете использовать @JoinColumn(name = "shipment_id") , поскольку это относится к PK целевого объекта

4. Это сработало, даже лучше! Следует обновить ваш ответ, чтобы отразить это. Окончательный код должен быть: @OneToOne @MapsId @JoinColumn(name = "shipment_id") private Shipment shipment;