私は、他の列から離れたorderId、locationIdおよびsequenceNum列を持つテーブルを持っています。これら3つの列は、主キー制約の一部です。 sequenceNum列はorderId/locationIdの組み合わせに対して増分し、次のorderId/locationIdに対して1から再開します。したがって、sequenceNumの生成は、orderId/locationIdの組み合わせに対してmax(sequenceNum)+1に基づいて行う必要があります。これはJPA @Embeddableと@EmbeddedIdでモデル化できますか? orderId/locationIdの組み合わせのシーケンスを1に戻すにはどうすればよいですか?シーケンスフィールドを持つ複合主キーのモデリング
0
A
答えて
0
ユーザーを休止状態にすると、この例を使用できます。そうでない場合は、使用しているAPIでシーケンスジェネレータを見つけ、同じロジックを使用します。
Identifiable.java
package my.app.hibernate;
import java.io.Serializable;
public interface Identifiable<T extends Serializable> {
T getId();
}
CompositeKeyEntity.java
package my.app.hibernate;
import java.io.Serializable;
public interface CompositeKeyEntity<T extends Serializable> extends Identifiable<T> {
}
SingleKeyEntity.java
package my.app.hibernate;
import java.io.Serializable;
public interface SingleKeyEntity<T extends Serializable> extends Identifiable<T> {
}
AssignedIdentityGenerator.java
package my.app.hibernate;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.IdentityGenerator;
import org.hibernate.internal.CriteriaImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.util.FieldUtils;
public class AssignedIdentityGenerator extends IdentityGenerator {
private static final String ID_FIELD_NAME = "id";
private final Logger LOG = LoggerFactory.getLogger(this.getClass());
private Field sequenceField;
private String entityClassName;
@Override
public Serializable generate(SessionImplementor session, Object obj) {
@SuppressWarnings("unchecked")
Identifiable<Serializable> identifiable = (Identifiable<Serializable>)obj;
entityClassName = obj.getClass().getName();
Criteria criteria = new CriteriaImpl(entityClassName, session);
criteria.setReadOnly(true);
Object toSet = null;
if (identifiable instanceof CompositeKeyEntity) {
Serializable id = identifiable.getId();
if (id != null) {
String embaddebleClassName = id.getClass().getName();
buildCriteriaForEmbeddedId(id, embaddebleClassName, criteria);
toSet = id;
}
} else if (obj instanceof SingleKeyEntity) {
toSet = identifiable;
sequenceField = FieldUtils.getField(identifiable.getClass(), ID_FIELD_NAME);
buildCriteriaForSingleId(criteria);
}
Number one = castToSequenceNumberType(1L);
Number value = (Number) criteria.uniqueResult();
if(value != null) {
value = castToSequenceNumberType(value.longValue() + one.longValue());
setFieldValue(sequenceField, value, toSet);
} else {
value = one;
setFieldValue(sequenceField, value, toSet);
}
return identifiable.getId();
}
private void buildCriteriaForSingleId(Criteria criteria) {
criteria.setProjection(Projections.max(ID_FIELD_NAME).as("seq"));
}
private void buildCriteriaForEmbeddedId(Serializable id, String embaddebleClassName, Criteria criteria) {
List<Field> fields = Arrays.asList(id.getClass().getDeclaredFields());
class Utils {
Field field;
boolean numberFound = false;
}
final Utils utils = new Utils();
for (Field field : fields) {
if ("serialVersionUID".equals(field.getName()) || "$jacocoData".equals(field.getName())) {
continue;
}
if (Number.class.isAssignableFrom(field.getType())) {
if (utils.numberFound) {
throw new IllegalArgumentException(
embaddebleClassName + " has more then one sequence field: " + field.getName() + ", "
+ utils.field.getName() + ",...");
}
utils.numberFound = true;
utils.field = field;
sequenceField = field;
criteria.setProjection(Projections.max(ID_FIELD_NAME + "." + sequenceField.getName()).as("seq"));
} else {
criteria.add(Restrictions.eq(ID_FIELD_NAME + "." + field.getName(), getFieldValue(field, id)));
}
}
}
private Number castToSequenceNumberType(Number n) {
return (Number) sequenceField.getType().cast(n);
}
private void setFieldValue(Field field, Object value, Object to) {
try {
field.setAccessible(true);
field.set(to, value);
} catch (IllegalArgumentException | IllegalAccessException e) {
LOG.error(e.getMessage(), e);
}
}
private Object getFieldValue(Field field, Object from) {
try {
field.setAccessible(true);
return field.get(from);
} catch (IllegalArgumentException | IllegalAccessException e) {
LOG.error(e.getMessage(), e);
}
return null;
}
}
Customer.java
package my.app.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;
import my.app.hibernate.SingleKeyEntity;
@Entity(name = "whatever_entity_name")
@GenericGenerator(name = "WHATEVER_NAMED_GENERATOR", strategy = "my.app.hibernate.AssignedIdentityGenerator")
public class Customer implements SingleKeyEntity<Long> {
@Id
@GeneratedValue(generator = "WHATEVER_NAMED_GENERATOR")
private Long id;
@Column(nullable = false)
private String name;
}
CustomerItemsId.java(それはSingleKeyEntity例を次のようにItem.javaがommited)
package my.app.entities;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Embeddable
public class CustomerItemsId implements Serializable {
private static final long serialVersionUID = 1L; //generate one
@ManyToOne
@JoinColumn(name = "customer_id")
private Customer customer;
@ManyToOne
@JoinColumn(name = "item_id")
private Item item;
private Long seq; //name as you wish
}
CustomerItems.java
package my.app.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;
import my.app.hibernate.CompositeKeyEntity;
@Entity(name = "whatever_entity_name")
@GenericGenerator(name = "WHATEVER_NAMED_GENERATOR", strategy = "my.app.hibernate.AssignedIdentityGenerator")
public class CustomerItems implements CompositeKeyEntity<CustomerItemsId> {
@GeneratedValue(generator = "WHATEVER_NAMED_GENERATOR")
private CustomerItems id;
@Column(nullable = false)
private String randomColumn1;
@Column(nullable = false)
private String randomColumn2;
}
関連する問題
- 1. 外部キーを持つ複合主キーを保存する
- 2. 複合主キー
- 3. YII2:複数の主キーを持つドロップダウンリスト
- 4. 複合主キーのテーブルでMAX(DATE)を持つGROUP BY
- 5. Nullを許可する列を持つ複合主キー
- 6. Yii複合主キーのモデル
- 7. SQLAlchemyの:複合主キー
- 8. 複合主キーの質問
- 9. Spring OneToMany複合キーを持つ別のキーとの複合キー
- 10. ドロップ複合主キー制約
- 11. 複合主キーは、TopLink
- 12. 2つの主キーを持つハッシュテーブル
- 13. SQL:追加の実行シーケンスフィールドを持つ行の複製
- 14. GWT RequestFactory:複合主キーを持つエンティティを処理する方法
- 15. 私は、次の3つのテーブル持っている複合主キー
- 16. 複数の主キーを持つデータリスト行を削除
- 17. クラスタ化された主キーを持つ重複レコードの削除
- 18. AddOrUpdateのEF複合主キー違反
- 19. 複合キーを持つテーブルのCakePHPビュー
- 20. JPA 2 - 複合主キーの1つのフィールドのみを含む外部キー?
- 21. JPA @ManyToMany結合テーブルの主要な複合キーを持たない関係
- 22. Hibernateで2つの多対1キーを持つ複合キー
- 23. MySQL:パターン(主キー)を持つID
- 24. 複合主キーかどうか
- 25. JPA/Hibernateは複合主キーForiegn ManyToOneマッピング
- 26. ASP.NETコアを持つ流暢なAPIの外部キーからなる複合主キーの作成
- 27. 主キーの結合
- 28. 2つの主キーを持つ中間結合テーブルを使用したマッピング
- 29. 外部キーを含む複合主キーを持つことは悪い考えですか?
- 30. mysqlの複合主キーとの外部キー関係