【问题标题】:How to create composite primary key with one auto generated value?如何使用一个自动生成的值创建复合主键?
【发布时间】:2018-12-25 19:05:45
【问题描述】:
I am trying to map entity with my existing database table which is having two primary keys.

Out of two keys, one primary key is auto generated.

I am using `Spring Boot`, `JPA`, `Hibernate` and `MySQL`. I have used `@IdClass` to map with the composite primary class (with public constructor, setter/getters, same property names, equals and hash code methods).

`org.springframework.data.repository.CrudRepository` save method to save the entity.  

代码如下:sn-p。

@Entity
@Table(name = "data")
@IdClass(DataKey.class)
public class DeviceData {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    private BigInteger id;
    @Column(name="name")
    private String name;
    @Id
    @Column(name="device_id")
    private int deviceId;
    getters/setters
}
public class DataKey implements Serializable {
    private static final long serialVersionUID = 1L;
    private BigInteger id;
    private int deviceId;
    //setter/getters
    public DataKey() {
    }
    public DataKey(BigInteger id, int deviceId) {
        this.id = id;
        this.deviceId = deviceId;
    }
    public int hashCode() {
        return Objects.hash(id, deviceId);
    }
    public boolean equals(Object obj) {
        if (obj == this)
            return true;
        if (!(obj instanceof DataKey))
            return false;
        DataKey dk = (DataKey) obj;
        return dk.id.equals(this.id) && dk.deviceId == (this.deviceId);}
}
I am using org.springframework.data.repository.CrudRepository save method for persisting the entity.

设备数据数据=新设备数据();

data.setName("device1"); data.setDeviceId("1123");

dao.save(数据); //dao 扩展 crudrepository 接口。

但我遇到以下错误:

    org.springframework.orm.jpa.JpaSystemException: Could not set field 
    value [POST_INSERT_INDICATOR] value by reflection.[class DataKey.id]
    setter of DataKey.id; nested exception is
    org.hibernate.PropertyAccessException: Could not set field value
    [POST_INSERT_INDICATOR] value by reflection : [class class DataKey.id]
    setter of class DataKey.id.

原因:java.lang.IllegalArgumentException:无法将 java.math.BigInteger 字段 DataKey.id 设置为 org.hibernate.id.IdentifierGeneratorHelper$2

【问题讨论】:

  • 每次创建对象都需要新的id还是要自己控制?
  • 你发布你的代码怎么样?!
  • @Id不需要匹配数据库PK:见stackoverflow.com/a/46370549/1356423
  • @AlanHay 感谢您的重播。是的,它必须与 db pk 匹配,否则从 db 读取数据时会出现问题。对于某些条目,我们正在设置 id(多行使用相同的 id不同的设备ID)和设备ID手动。因此,在获取所有设备ID的同时,休眠返回具有相同设备ID的所有行。
  • @user2247791 有什么更新吗?

标签: mysql hibernate jpa composite-key autogeneratecolumn


【解决方案1】:
I have achieved this by creating a one orderId class with parameters -- Mysql
@Getter
@Setter
public class OrderId implements Serializable {

    private int oId;
    private int customerId;
    private int productId;

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        OrderId orderId = (OrderId) o;
        return oId == orderId.oId && customerId == orderId.customerId && productId == orderId.productId;
    }

    @Override
    public int hashCode() {
        return Objects.hash(oId, customerId, productId);

    }

the class OrderData with orderid as auto generated field in mysql
@Entity
@Table(name = "OrderData")
@Getter
@Setter
@NoArgsConstructor
@IdClass(OrderId.class)
public class OrderData{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int oId;
    @Id
    private int customerId;
    @Id
    private int productId;
    private int quanity;
    private String paymentMode;
    private String orderStatus;

}

【讨论】:

    【解决方案2】:

    我能够使用序列生成器解决它。

        @Id
        @SequenceGenerator(name="my_seq", sequenceName="my_db_table_seq", allocationSize=1)
        @GeneratedValue(generator = "my_seq")
        @Column(name = "id", updatable = false, nullable = false)
        private BigInteger id
    
    

    在我的例子中,我使用的是 Postgres,我的表以 SERIAL 作为列数据类型在 pg_catalog.pg_sequences 表中也有相应的条目(例如,在上面的示例中为 my_db_table_seq)。

    如果你没有指定一个特定的命名序列生成器(并且只在你的@Id 列上使用@GeneratedValue(strategy = GenerationType.SEQUENCE)),看起来Hibernate 默认使用一个名为hibernate_sequence 的序列生成器,我已经看到一些建议来运行db 命令CREATE SEQUENCE hibernate_sequence START 1 以获取在数据库中创建的内容。但这将对通过 Hibernate 插入行的每个表使用 same 序列,因此可能不是一个好主意。最好使用在数据库中为该表创建的序列,然后使用@SequenceGenerator 注释明确。

    在具有@IdClass 的实体的复合键中使用@GeneratedValue(strategy = GenerationType.IDENTITY) 似乎确实存在问题,所以如果Hibernate 可以支持这一点会很好。

    但看起来序列生成器是一种有效的解决方法,所以这就是我要使用的方法。

    【讨论】:

      【解决方案3】:

      我在我的一个项目中也尝试过相同的方法,但最终我发现在 JPA 中无法自动生成关键属性之一(如果是复合主键)。所以,我通过在查询的帮助下调用序列来单独完成。

      【讨论】:

      • 感谢您的回复。您是如何生成序列的?能否解释一下。我怀疑,序列可能在并发请求中重复。
      • 您需要在数据库中创建一个序列,然后使用本机查询来获取下一个值。比如:select nextval('my_sequence');获取的下一个值可以在您的 id 属性中设置
      • 当然可以生成多字段PK的一个组件
      • @BillyFrost 感谢您的回复。请您解释一下我该如何实现。
      • @user2247791 当你用你的实际代码更新你的问题时,就有了评论的基础。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-04
      • 2014-06-17
      • 1970-01-01
      • 1970-01-01
      • 2017-07-22
      • 2020-10-27
      相关资源
      最近更新 更多