Почему ленивый объект init является нулевым, когда назначается DTO внутри границы транзакции? - PullRequest
0 голосов
/ 11 октября 2019

Я портирую свой прежний код на приложение Spring boot + angular, которое раньше было spring + angular js. В моем pojo ленивые отношения @ManyToOne. Когда я пытаюсь создать объект DTO из исходного объекта, дочерний объект внутри оригинального объекта при отправке клиенту становится пустым. В моем унаследованном приложении тот же код работает отлично.

Если я делаю это нетерпеливым или вызываю sysout для этого дочернего элемента перед созданием DTO, то это работает, вероятно, потому, что getters дочернего объекта вызывается внутренне.

Родительский объект

public class ComponentInfo implements Serializable{

    private static final long serialVersionUID = -1135710750835719391L;

    @Id
    @Column(name="TAGGING_KEY")
    private String taggingKey;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "COMPONENT_CONFIG_ID",nullable = true)
    private ReportComponentConfig componentConfig;

    @Column(name = "DESCRIPTION", length = 200)
    private String description;

    @Column(name = "ORIGINAL_FILE_NAME",length=50)
    private String originalFileName;

    @Column(name = "OVERRIDE_DOCUMENT")
    private Boolean overrideDocument = false;

    @Column(name = "START_DATE")
    private Date startDate;

    @OneToMany(mappedBy="componentInfo",cascade=CascadeType.ALL,orphanRemoval=true)
    private List<TransactionComponentInfo> transactionComponentInfo = new ArrayList<>(0);

    @Column(name = "SHOW_GLOBAL")
    private Boolean showGlobal = false;
}

Дочерний объект

public class ReportComponentConfig {

    @Id
    @TableGenerator(name = "COMPONENT_CONFIG_ID", table = "ID_GENERATOR", pkColumnName = "GEN_KEY", valueColumnName = "GEN_VALUE", pkColumnValue = "COMPONENT_CONFIG_ID", allocationSize = 1, initialValue = 1)
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "COMPONENT_CONFIG_ID")
    @Column(name = "COMPONENT_CONFIG_ID", unique = true, nullable = false)
    private int id;

    @Column(name = "NAME", nullable = false, length = 200)
    private String name;

    @Column(name = "TAG", nullable = false, length = 200)
    private String tag;

    @Column(name = "COMP_CONFIG", nullable = false, columnDefinition = "VARCHAR(MAX)")
    private String config;

    @Column(name = "PUBLISHED_CONFIG", columnDefinition = "VARCHAR(MAX)")
    private String publishedConfig;

    @Column(name = "IS_PUBLISHED")
    private boolean published = false;

    @ManyToOne
    @JoinColumn(name = "COMPONENT_ID", nullable = false)
    private Component component;

    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "CONFIG_REPORT_MAPPING", joinColumns = @JoinColumn(name = "COMPONENT_CONFIG_ID"))
    @Column(name = "REPORT_ID")
    private Set<Long> reports = new HashSet<>(0);

    @ElementCollection(fetch = FetchType.LAZY)
    @CollectionTable(name = "CONFIG_TRANSACTION_MAPPING", joinColumns = @JoinColumn(name = "COMPONENT_CONFIG_ID"))
    @Column(name = "TRANSACTION_ID")
    private Set<Long> transactions = new HashSet<>(0);

    @Column(name = "VIEWS", columnDefinition = "VARCHAR(MAX)")
    private String views;
}

DTO

public class ComponentInfoDTO implements Cloneable {

    private ReportComponentConfig componentConfig;

    private String taggingKey;

    private String description;

    private String originalFileName;

    private Date startDate;

    private Boolean overrideDocument;

    private Boolean showGlobal;

    private ComponentInfoDTO parentComponentInfo;

    public ComponentInfoDTO() {
    }

    public ComponentInfoDTO(ComponentInfo ci, TransactionComponentInfo transactionComponentInfo) {
        this.componentConfig = ci.getComponentConfig();//this is object is null
        this.taggingKey = ci.getTaggingKey();
        this.description = ci.getDescription();
        this.originalFileName = ci.getOriginalFileName();
        this.startDate = ci.getStartDate();
        this.overrideDocument = ci.getOverrideDocument();
        this.showGlobal = ci.getShowGlobal();
        if (transactionComponentInfo != null) {
            this.parentComponentInfo = this.clone();
            this.startDate = transactionComponentInfo.getStartDate();
            this.overrideDocument = transactionComponentInfo.getOverrideDocument();
            this.description = transactionComponentInfo.getDescription();
            this.originalFileName = transactionComponentInfo.getOriginalFileName();
            this.showGlobal = true;
        }

    }
}

Новое кодовое изображение enter image description here

Старый код изображения enter image description here

Редактировать: оба одинаковы, но в старом случае я получаю дочерний объект на стороне клиента, а в новом случае я получаю ноль.

Это данные, которые я получаю в моем старом приложении с ленивым init

[ {
  "componentConfig" : {
    "id" : 3,
    "name" : "Monthly Origination By Region",
    "tag" : "CHART_monthlyOriginationByRegion",
    "config" : "xyz",
    "published" : true,
    "component" : {
      "id" : "CHART",
      "name" : "Chart",
      "defaultConfig" : null,
      "htmlTag" : "<chart></chart>",
      "filePath" : "chart/chart.component.js",
      "dependentScriptsSrc" : [ ],
      "dependencies" : null
    },
    "reports" : [ 3 ],
    "transactions" : [ 2 ],
    "views" : "{\"monthlyOriginationByRegion\": {\"key\": \"MONTHLY_ORIGINATION_BY_REGION\"}}"
  },
  "taggingKey" : "3",
  "description" : "asdfasd\nasdfadf",
  "originalFileName" : "Citi Tape - 2141 - GEBL0501 - 2019 Oct 04.xlsm",
  "startDate" : "2019-10-28T18:30:00.000+0000",
  "overrideDocument" : true,
  "showGlobal" : true,
  "parentComponentInfo" : null
} ]

Это данные в новом приложении

[ {
  "componentConfig" : null,
  "taggingKey" : "3",
  "description" : "asdfasd\nasdfadf",
  "originalFileName" : "Citi Tape - 2141 - GEBL0501 - 2019 Oct 04.xlsm",
  "startDate" : "2019-10-28T18:30:00.000+0000",
  "overrideDocument" : true,
  "showGlobal" : true,
  "parentComponentInfo" : null
} ]

Конфигурация компонента не должна быть нулевой, если она сделананетерпеливый выбор, это работает в новом приложении, но в моем более старом приложении это работает с отложенной выборкой.

1 Ответ

0 голосов
/ 11 октября 2019

В окне отладчика вы видите HibernateProxy. Поля этого прокси никогда не инициализируются! Получатели перехватываются и делегируются загруженному объекту, который находится где-то внутри прокси.

Это означает, что вам никогда не придется напрямую вызывать поля, так как вы не знаете, является ли объект прокси или вашей загруженной сущностью. Вам всегда нужно работать на добытчиков.

Как вы отображаете сущность в DTO? Скорее всего, вы используете полевой доступ, в то время как вы должны использовать геттеры.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...