Spring boot: как сохранить данные в определенный 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>, состоящий из 2 строк, в строке есть debitAmount = C и operationNature = Virement, а во второй строке есть debitAmount = C и operationNature = Espece. Моя цель — сохранить каждую строку в определенном DTYPE. пример первая строка должна сохраняться в OperationCreditEntity table DTYPE = Virement, а вторая должна сохраняться в OperationCreditEntity table DTYPE = Espece

Я не понимаю вопроса - вы упоминаете строки БД, но у вас есть классы и сущности Java. Разве вы не создаете экземпляры OperationEspecesEntity, OperationVirementEntity и OperationChequeEntity для своих данных? Зачем дублировать столбцы из StatementLinesEntity в отдельную таблицу OperationCreditEntity (при условии, что dateOperation~operationDate, DTYPE~operationNature). Один должен просто ссылаться на другой (нормализация БД) — StatementLinesEntity должен иметь ссылку на OperationCreditEntity вместо того, чтобы напрямую хранить операцию OperationNature.

Chris 01.04.2022 18:35

Да, почему я не создаю экземпляры, потому что я создаю службу, которая будет отвечать только за эти операции, все транзакции будут перенесены в таблицу OperationCreditEntity, этот процесс будет выполняться автоматически, это как вы даете 100000 строк, и эти службы будут помещать каждая строка к определенному DTYPE на основе этих двух условий: должна иметь C в debitAmount и может содержать одно из этих 3 слов: Virement or Espece or Cheque в operationNature.

BAKHALED Ibrahim 01.04.2022 19:27

Как я уже сказал, это служба, отвечающая за этот процесс, дело в том, что я не нашел логики, как достичь этой цели. На самом деле я застрял в этом вопросе около 2 дней без решений. Если вы что-то знаете, пожалуйста, скажите

BAKHALED Ibrahim 01.04.2022 19:27

До сих пор не понятно - что у вас сейчас конкретно? Является ли это миграцией существующих данных таблицы StatementLinesEntity в другой формат таблицы, или вы берете пользовательские данные и задаетесь вопросом, как превратить ваши существующие данные StatementLinesEntity в эти квази-объекты данных OperationCreditEntity java; Цикл for, использующий ваш экземпляр StatementLinesEntity для создания из него экземпляра OperationCreditEntity с вызовом spring repo.save() для результата

Chris 01.04.2022 19:51

Если вы контролируете сами входящие данные (например, JSON), вы можете просто встроить их непосредственно в StatementLinesEntity, который ссылается на OperationCreditEntity, синтаксические анализаторы могут построить его для вас с небольшими изменениями, на которые я намекал, чтобы вам не нужно было дублировать данные dateOperation и operationNature в обе сущности/таблицы

Chris 01.04.2022 19:52

Хорошо, рассмотрим этот сценарий. У меня есть таблица StatementLinesEntity в mysql с 100000 записей. В моей таблице будут все поля с данными (id, date, bigDecimal amount, C, Virement), где C относится к debitAmount, а Virement относится к operationNature, в моей базе данных у меня есть еще 4 таблицы OperationCreditEntity с аннотацией @Inheritance типа SINGLE_TABLE и 3 другие таблицы, которые наследуются от нее (OperationVirementEntity,OperationChequeEntity,OperationEs‌​peceEntity), пока все ясно.

BAKHALED Ibrahim 01.04.2022 20:12

Теперь в моем сервисе я пойду в базу данных и пройдусь по всем строкам StatementLinesEntity, а затем отфильтрую каждую строку, в которой есть debitAmount == C и operationNature == Virement or Cheque or Espece (это могут быть другие данные, которые не имеют этих условий, я буду их игнорировать) после фильтрации и возврата нового Список (список, в котором есть все debitAmount == C, я хочу сохранить каждую запись в OperationCreditEntity в определенном DTYPE на основе operationNature, например: первая запись в списке имеет debitAmount == C и operationNature == Virement мой сервис сохраняет эту строку как DTYPE = Virement

BAKHALED Ibrahim 01.04.2022 20:19

в таблице OperationCreditEntity. теперь вторая запись имеет debitAmount == C и operationNature == Cheque, служба должна сохранить эту строку как DTYPE = Cheque в таблице OperationCreditEntity. третья запись имеет debitAmount == C и operationNature == Espece, служба должна сохранять эту строку как DTYPE = Espece и так далее ... и каждая строка, сохраненная в таблице OperationCreditEntity, будет иметь FK StatementLinesEntity, потому что у меня есть @OneToOne с StatementLinesEntity в OperationCreditEntity. Я не знаю, если вы получите идею.

BAKHALED Ibrahim 01.04.2022 20:23

Вы смешиваете «сущность» или класс данных Java с таблицей. Насколько я понимаю, у вас всего 2 таблицы. Один для StatementLinesEntity, а другой для данных OperationCreditEntity. То, что вы помещаете в эти таблицы, кажется мне, немного перекрывается, и, кажется, существует отношение 1: 1. Таким образом, если у вас есть 100 тыс. строк StatementLinesEntity, у вас, вероятно, будет 100 тыс. строк OperationCreditEntity, дублирующих данные OperationNature в обоих. Независимо от того, где вы застряли? Прочтите/примите свой StatementLinesEntity, создайте из него экземпляры OperationCreditEntity и вызовите save.

Chris 01.04.2022 20:52

Вы имеете в виду, что я должен перебрать список и создать экземпляр OperationCreditEntity, а затем вызвать метод сохранения для OperationCreditEntity?

BAKHALED Ibrahim 01.04.2022 21:11

Есть ли способ, которым я могу установить дискриминатор программно, то есть я зацикливаю каждую запись, в которой я устанавливаю дискриминатор на свой собственный DTYPE. Есть ли решение для этого?

BAKHALED Ibrahim 01.04.2022 21:14

Я думаю, вы запутались в наследовании Java. Смотрите мой ответ, но поймите, что new OperationChequeEntity() является экземпляром OperationCreditEntity. JPA обрабатывает запись DTYPE для вас на основе DiscriminatorValue в подклассах. Вам никогда не нужно создавать «новый OperationCreditEntity()», поскольку он не имеет значения для вашего приложения — поэтому я пометил его как абстрактный в своем ответе. Если вы выполняете запрос к таблице OperationCreditEntity, никогда не должно быть строк, которые сопоставляются с OperationCreditEntity — для нее нет возможной записи DTYPE.

Chris 01.04.2022 21:29
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
0
12
32
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Модель для меня должна быть больше похожа на:

@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 (который может быть любым из его подклассов). Нет необходимости управлять, анализировать или обрабатывать строки String operationNature напрямую, так как тип операции будет определять характер операции.

Это может изменить другие подписи, сериализацию (например, JSON), поэтому, если вы не можете использовать это и «застряли» с существующим представлением данных 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;
}

Просто вызовите save, используя репозиторий OperationCreditEntity, когда бы вы ни вызывали этот метод, чтобы поместить его в тот же транзакционный контекст, в который вы вносите изменения. Также обратите внимание, что в этих подклассах OperationCreditEntity есть данные, которые вам нужно найти, чтобы заполнить их самостоятельно; Я лично думаю, что эти данные, вероятно, будут привязаны к данным, доступным при определении/создании StatementLinesEntity, поэтому их следует генерировать/создавать тогда, а не постфактум, но это зависит от вас.

Добавлено для полноты: Да, вы можете получить доступ к столбцу, используемому для хранения значений дискриминатора, непосредственно в базовом классе сущностей. Ничто не мешает и не мешает вам отображать столбец, как любой другой столбец базы данных. Для 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;
}

Заметьте, я пометил это как вставляемый/обновляемый=ложный. Это зависит от поставщика, если он жалуется на управление этим значением таким образом; многие пытаются сделать это в надежде изменить это. Изменение типа объекта не поддерживается. Caterpillar не станет бабочкой, просто изменив строковое значение. Любые кэши, которые содержат OperationCreditEntity или какой-либо конкретный тип подкласса, не волшебным образом изменят тип объекта; JPA требует, чтобы вы удалили объект и создали новый экземпляр (соответствующего класса) для этих данных, желательно после сброса операции удаления.

Также обратите внимание, что вы можете запрашивать и использовать выражения типа сущности (TYPE) без столбца или другого сопоставления для него.

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

Другие вопросы по теме