Spring 引导:如何将数据保存到特定的 DTYPE

Spring boot: How to Save data to specific DTYPE

我有这个实体:

public class StatementLinesEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long statementLinesId;
@CreationTimestamp
@Temporal(TemporalType.DATE)
private Date dateOperation;
private String operationNature;
private BigDecimal amount;
private String debitAmount;

并且此实体具有 SINGLE_TABLE 类型的继承:

  @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
  public class OperationCreditEntity {

  @Id
  @Column(nullable = false, updatable = false)
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long operationCreditId;
  @CreatedDate
  private Date operationDate;
  @OneToOne
  private StatementLinesEntity statementLine;

这 3 个实体继承了它:

  @Entity
  @DiscriminatorValue("Espece")
  public class OperationEspecesEntity extends OperationCreditEntity {
  private String cin;
  private String nomEmetteur;
  private String prenomEmetteur;
  =============================
  @DiscriminatorValue("Virement")
  public class OperationVirementEntity extends OperationCreditEntity {
  private String rib;
  ===========================
  @Entity
  @DiscriminatorValue("Cheque")
  public class OperationChequeEntity extends OperationCreditEntity{
  private int numeroCheque;

假设我有一个由两行组成的 List<StatementLinesEntity>,第一行有 debitAmount = CoperationNature = Virement,第二行有 debitAmount = CoperationNature = Espece。我的目标是在特定 DTYPE 中坚持每一行。例子 第一行应保留在 OperationCreditEntity table DTYPE = Virement 中,第二行应保留在 OperationCreditEntity table DTYPE = Espece

我的模型应该更像是:

@Entity
public class StatementLinesEntity {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long statementLinesId;
  @CreationTimestamp
  @Temporal(TemporalType.DATE)
  private Date dateOperation;
  @OneToOne(mappedBy = "statementLine")
  private OperationCreditEntity operation;
  private BigDecimal amount;
  private String debitAmount;
}

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
abstract public class OperationCreditEntity {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long operationCreditId;
  @CreatedDate
  private Date operationDate;
  @OneToOne
  private StatementLinesEntity statementLine;
}

任何采用 StatementLinesEntity 实例的方法都可以采用引用 OperationCreditEntity 实例(可以是其子classes 之一)的方法。无需直接管理、解析或处理String operationNature字符串,操作类型决定操作性质

这可能会改变其他签名、序列化(例如 JSON),因此如果您不能使用它并且 'stuck' 与您现有的 StatementLinesEntity 数据表示形式,您需要处理如何从该数据创建您的 OperationCreditEntity 实例。没有工具可以自动为您完成。它就像以下形式的实用程序一样简单:

OperationCreditEntity createOperationInstance(StatementLinesEntity statementLine) {
  String operationNature = statementLine.getOperationNature();
  OperationCreditEntity returnVal = null;
  if "Espece".equals(operationNature) {
    returnVal = new OperationEspecesEntity();
  } else if "Virement".equals(operationNature) {
    returnVal = new OperationVirementEntity();
  } else if "Cheque".equals(operationNature) {
    returnVal = new OperationChequeEntity();
  } else {
    throw new IllegalStateException();
  }
  returnVal.setStatementLine(statementLine);

  return returnVal;
}

当您调用此方法时,只需使用您的 OperationCreditEntity 存储库调用保存,即可将其放入您正在更改的同一事务上下文中。另请注意,那些 OperationCreditEntity subclasses 具有您需要找到自己填写的方法的数据;我个人认为此数据可能与 defining/creating StatementLinesEntity 时可用的数据相关联,因此应该是 generated/created,而不是事后,但这取决于您。

添加只​​是为了完整: 是的,您可以直接在基本实体 class 中访问用于存储鉴别器值的列。没有什么能阻止或阻止您像映射任何其他数据库列那样映射该列。对于 Hibernate,它使用“DTYPE”,所以

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class OperationCreditEntity {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long operationCreditId;
  @CreatedDate
  private Date operationDate;
  @Column(name="DTYPE",insertable=false, updatable=false)
  private String typeValue;
}

请注意,我将此标记为 insertable/updatable=false。如果它抱怨以这种方式控制此值,则它是特定于提供者的;许多人试图这样做,希望能改变它。不支持更改实体 'type'。 Caterpillar 不会仅仅通过更改字符串值就变成 Butterfly。任何包含 OperationCreditEntity 或某些特定 subclass 类型的缓存都不会神奇地更改对象类型; JPA 要求您删除实体并为该数据创建一个新实例(正确的 class),最好是在刷新删除操作之后。

另请注意,您可以在没有列或其他映射的情况下查询和使用实体类型表达式 (TYPE)。

  "Select line from OperationCreditEntity operation join operation.statementLine line where TYPE(operation) IN (OperationEspecesEntity, OperationChequeEntity) and line.somethingElse = :someValue"