Составной ключ JPA + последовательность
-
04-07-2019 - |
Вопрос
Возможно ли в простых расширениях JPA или JPA+Hibernate объявить составной ключ, где элементом составного ключа является последовательность?
Это мой составной класс:
@Embeddable
public class IntegrationEJBPk implements Serializable {
//...
@ManyToOne(cascade = {}, fetch = FetchType.EAGER)
@JoinColumn(name = "APPLICATION")
public ApplicationEJB getApplication() {
return application;
}
@Column(name = "ENTITY", unique = false, nullable = false, insertable = true, updatable = true)
public String getEntity() {
return entity;
}
@GeneratedValue(strategy = GenerationType.AUTO, generator = "INTEGRATION_ID_GEN")
@SequenceGenerator(name = "INTEGRATION_ID_GEN", sequenceName = "OMP_INTEGRATION_CANONICAL_SEQ")
@Column(name = "CANONICAL_ID", unique = false, nullable = false, insertable = true, updatable = true)
public String getCanonicalId() {
return canonicalId;
}
@Column(name = "NATIVE_ID", unique = false, nullable = false, insertable = true, updatable = true)
public String getNativeId() {
return nativeId;
}
@Column(name = "NATIVE_KEY", unique = false, nullable = false, insertable = true, updatable = true)
public String getNativeKey() {
return nativeKey;
}
//...
}
Я уже предоставил значения для application
, entity
, nativeId
и nativeKey
.Я хочу создать объект, подобный приведенному ниже:
IntegrationEJB i1 = new IntegrationEJB();
i1.setIntegrationId(new IntegrationEJBPk());
i1.getIntegrationId().setApplication(app1);
i1.getIntegrationId().setEntity("Entity");
i1.getIntegrationId().setNativeId("Nid");
i1.getIntegrationId().setNativeKey("NK");
И когда я звоню em.persist(i1
), я хочу, чтобы canonicalId
генерируется и вставляется интеграция.
Это возможно?Если да, то какой простой способ?(Я предпочитаю не использовать ключи, предоставленные приложением, или собственный sql).
Решение
Я считаю, что это невозможно с простым JPA.
Другие советы
Использование @GeneratedValue для составных ПК не указано в спецификации JPA 2.
Из спецификации JPA:
11.1.17 Аннотация GeneratedValue
Аннотация GeneratedValue позволяет указать Стратегии генерации значений первичных ключей.Тем GeneratedValue может быть применена к свойству первичного ключа или сущности или отображенного суперкласса в сочетании с Id аннотация. [97] Использование аннотации GeneratedValue только Требуется для поддержки простых первичных ключей.Использование метода Аннотация GeneratedValue не поддерживается для производных первичных ключей.
Обратите внимание, что в другом сценарии у вас может быть родительский объект с простым PK (@Id), который использует @GeneratedValue, а затем иметь дочерний объект с составным PK, включающим сгенерированный идентификатор родительского объекта, а также еще один столбец.
- Дайте дочернему элементу отношение @ManyToOne к родительскому объекту, чтобы он унаследовал сгенерированный идентификатор в столбце FK.
- Затем дайте дочернему элементу составной ПК через @IdClass, указанный для сущности, плюс два столбца @Id внутри сущности.
@Entity public class ParentEntity {
@Id
@GenerateValue(IDENTITY) // If using DB auto-increment or similar
int id;
// ...
}
@Entity @IdClass(ChildId.class) public class ChildEntity { // The child table will have a composite PK: // (parent_ID, child_name) @Id @ManyToOne int parentEntity;
@Id
String childName;
String favoriteColor; // plus other columns
// ...
}
// child Id attributes have the same name as the child entity // however the types change to match the underlying PK attributes // (change ParentEntity to int) public class ChildId implements Serializable {
int parentEntity;
String childName;
public ChildId() { //... }
// Add extra constructor & remove setter methods so Id objects are immutable
public ChildId(int parentEntity, String childName) { //... }
public int getParentEntity() { //... }
// make Id objects immutable:
// public void setParentEntity(int parentEntity) { //... }
public String getChildName() { //... }
// public void setChildName(String childName) { //... }
}
Попробуйте так:
@TableGenerator(name = "canonicalKeys", allocationSize = 1, initialValue = 1)
@GeneratedValue(strategy = GenerationType.TABLE, generator = "canonicalKeys")
@Column(name = "CANONICAL_ID", unique = false, nullable = false, insertable = true, updatable = true)
public String getCanonicalId() {
return canonicalId;
}
Таким образом, вместо использования последовательности вы можете использовать таблицу.
Я заметил, что создается впечатление, что вы создаете составной первичный ключ, подобный этому пример . Пока я пытался найти аналогичную проблему в моей собственной базе данных, я подумал, что, может быть, вы могли бы вызвать sql напрямую, как:
select nextval ('hibernate_sequence')
Полагаю, это было бы обманом; -)