Home > Net >  Spring boot: How to Save data to specific DTYPE
Spring boot: How to Save data to specific DTYPE

Time:04-02

I have this entity:

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;

And this entity has Inheritance of type 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;

And these 3 enteties inherite of it :

  @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;

Let's suppose I have a List<StatementLinesEntity> consist of 2 lines, on line has debitAmount = C and operationNature = Virement and second line has debitAmount = C and operationNature = Espece. My goal is to persist each line in a specific DTYPE. example first line should be persisted in OperationCreditEntity table DTYPE = Virement and the second should be persisted in OperationCreditEntity table DTYPE = Espece

CodePudding user response:

The model to me should be more like:

@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;
}

Any method then that takes in StatementLinesEntity instances can then take in one that references an OperationCreditEntity instance (which can be any one of its subclasses). There is no need to manage, parse or handle String operationNature strings directly, as the operation type will determine the operation nature.

This might change other signatures, serialization (such as JSON though), so if you can't use this and are 'stuck' with your existing StatementLinesEntity data representation YOU need to handle how to create your OperationCreditEntity instances from that data. There is no tool to automatically do it for you. It is as simple as a utility of the form:

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;
}

Just call save using your OperationCreditEntity repository when ever you call this method to get it put into the same transactional context you are making changes to. Also note, those OperationCreditEntity subclasses have data you will need to find a way to fill in on your own; I personally think this data will likely be tied to data available when defining/creating a StatementLinesEntity, so should be generated/created then, not after the fact, but that is up to you.

Added just to be complete: Yes, you can access the column used to store discriminator values directly in a base entity class. Nothing stops or prevents you from mapping the column as you would any other database column. For Hibernate, it uses "DTYPE", so

@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;
}

Notice I marked this as insertable/updatable=false though. It is provider specific if it complains about controlling this value in this way; many try to do so with the hope of changing it. Changing an entity 'type' is not supported. A Caterpillar does not become a Butterfly just by changing a string value. Any caches that hold OperationCreditEntity or some specific subclass type aren't magically going to have the object type changed; JPA requires you to delete the entity and create a new instance (of the proper class) for that data, preferably after flushing the delete operation.

Also note, you can query and use Entity Type Expressions (TYPE) without having a column or other mapping for it.

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