Как создать составной первичный ключ с одним автоматически сгенерированным значением?
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.
Фрагмент кода ниже.
@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.
Данные DeviceData= новые DeviceData ();
data.setName ("устройство1"); data.setDeviceId ("1123");
dao.save (данные); // Дао расширяющий интерфейс 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.
3 ответа
Мне удалось решить эту проблему с помощью генератора последовательности.
@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
в моем примере выше).
Если вы не укажете конкретный именованный генератор последовательности (и просто используете
@GeneratedValue(strategy = GenerationType.SEQUENCE)
на ваше
@Id
столбец), похоже, что по умолчанию для Hibernate используется тот, который называется
hibernate_sequence
, и я видел несколько предложений по запуску команды db
CREATE SEQUENCE hibernate_sequence START 1
чтобы получить то, что создано в базе данных. Но это будет использовать одну и ту же последовательность для каждой таблицы, которая вставляет строки через Hibernate, поэтому, вероятно, это не очень хорошая идея. Лучше всего использовать последовательность, которая создается в базе данных для этой таблицы, а затем явно указывать
@SequenceGenerator
аннотация.
Кажется, проблема с использованием
@GeneratedValue(strategy = GenerationType.IDENTITY)
в составном ключе объекта, имеющего
@IdClass
, поэтому было бы неплохо, если бы Hibernate мог это поддерживать.
Но похоже, что генератор последовательности - действительный обходной путь, так что я собираюсь с этим.
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;
}
Я также пытался сделать то же самое в одном из моих проектов, но в конце концов я обнаружил, что невозможно автоматически сгенерировать один из ключевых атрибутов (в случае составного первичного ключа) в JPA. Итак, я сделал это отдельно, вызвав последовательность с помощью запроса.