Как правильно отобразить отношения Родитель-ребенок (та же таблица) в Hibernate? - PullRequest
0 голосов
/ 08 марта 2020

У меня проблема с попыткой определить отношения между parent record и child records родителя. Я использую одну таблицу, где, если запись обновляется, вставляется новая, а старая становится неактивной - с parent_id, установленным на id из новой записи. Вот мой оператор CREATE для таблицы:

    CREATE TABLE `templates` (
      `id` int unsigned NOT NULL AUTO_INCREMENT,
      `region_id` int unsigned NOT NULL,
      `name` varchar(80) NOT NULL,
      `description` text,
      `is_active` tinyint unsigned NOT NULL DEFAULT '0',
      `parent_id` int unsigned DEFAULT NULL,
      `created_by` int unsigned DEFAULT NULL,
      `updated_by` int unsigned DEFAULT NULL,
      `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
      `modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      PRIMARY KEY (`id`),
      KEY `reg_id_idx` (`region_id`),
      CONSTRAINT `td_templates_cms_regions_2812` FOREIGN KEY (`region_id`) REFERENCES `cms_regions` (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

И Entity, который есть в моей java IDE:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.vw.asa.entities.template;

import com.vw.asa.entities.cms.CmsRegions;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * @author Barry Chapman
 */
@Entity
@Table(name = "templates", schema = "asa")
@XmlRootElement
@NamedQueries({
        @NamedQuery(name = "Templates.findAll", query = "SELECT t FROM Templates t"),
        @NamedQuery(name = "Templates.findById", query = "SELECT t FROM Templates t WHERE t.id = :id"),
        @NamedQuery(name = "Templates.findByName", query = "SELECT t FROM Templates t WHERE t.name = :name"),
        @NamedQuery(name = "Templates.findByIsActive", query = "SELECT t FROM Templates t WHERE t.isActive = :isActive"),
        @NamedQuery(name = "Templates.findByParentId", query = "SELECT t FROM Templates t WHERE t.parentId = :parentId"),
        @NamedQuery(name = "Templates.findByCreatedBy", query = "SELECT t FROM Templates t WHERE t.createdBy = :createdBy"),
        @NamedQuery(name = "Templates.findByUpdatedBy", query = "SELECT t FROM Templates t WHERE t.updatedBy = :updatedBy"),
        @NamedQuery(name = "Templates.findByCreated", query = "SELECT t FROM Templates t WHERE t.created = :created"),
        @NamedQuery(name = "Templates.findByModified", query = "SELECT t FROM Templates t WHERE t.modified = :modified")})
public class Templates implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;

    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 80)
    @Column(name = "name")
    private String name;

    @Lob
    @Size(max = 65535)
    @Column(name = "description")
    private String description;

    @Basic(optional = false)
    @NotNull
    @Column(name = "is_active")
    private short isActive;

    /*@Column(name = "parent_id")
    private Integer parentId;*/

    @Column(name = "created_by")
    private Integer createdBy;

    @Column(name = "updated_by")
    private Integer updatedBy;

    @Basic(optional = false)
    @NotNull
    @Column(name = "created")
    @Temporal(TemporalType.TIMESTAMP)
    private Date created;

    @Basic(optional = false)
    @NotNull
    @Column(name = "modified")
    @Temporal(TemporalType.TIMESTAMP)
    private Date modified;

    @JoinColumn(name = "region_id", referencedColumnName = "id")
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    private CmsRegions regionId;

    @JoinColumn(name = "parent_id", referencedColumnName = "id")
    @ManyToOne(optional = false,  fetch = FetchType.LAZY)
    private Integer parent_id;

    public Templates() {
    }

    public Templates(Integer id) {
        this.id = id;
    }

    public Templates(Integer id, String name, short isActive, Date created, Date modified) {
        this.id = id;
        this.name = name;
        this.isActive = isActive;
        this.created = created;
        this.modified = modified;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public short getIsActive() {
        return isActive;
    }

    public void setIsActive(short isActive) {
        this.isActive = isActive;
    }

    public Integer getParentId() {
        return getParent().getId();
    }

    public void setParentId(Integer parentId) {
        this.parent_id = parentId;
    }

    public Integer getCreatedBy() {
        return createdBy;
    }

    public void setCreatedBy(Integer createdBy) {
        this.createdBy = createdBy;
    }

    public Integer getUpdatedBy() {
        return updatedBy;
    }

    public void setUpdatedBy(Integer updatedBy) {
        this.updatedBy = updatedBy;
    }

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public Date getModified() {
        return modified;
    }

    public void setModified(Date modified) {
        this.modified = modified;
    }

    public Templates getParent() {
        return parent;
    }

    public void setParent(Templates parent) {
        this.parent = parent;
        this.parent_id = parent.getId();
    }

    public CmsRegions getRegionId() {
        return regionId;
    }

    public void setRegionId(CmsRegions regionId) {
        this.regionId = regionId;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Templates)) {
            return false;
        }
        Templates other = (Templates) object;
        return (this.id != null || other.id == null) && (this.id == null || this.id.equals(other.id));
    }

    @Override
    public String toString() {
        return "com.vw.asa.entities.Templates[ id=" + id + " ]";
    }

}

Я попытался добавить следующий блок в Объект, но он сгенерировал ошибку, указанную после этого блока:

    @JoinColumn(name = "parent_id", referencedColumnName = "id")
    @ManyToOne(optional = false,  fetch = FetchType.LAZY)
    private Integer parent;

Чтобы добавить это, я добавил следующий метод получения / установки:

    public Integer getParentId() {
        return getParent().getId();
    }

    public void setParentId(Integer parentId) {
        this.parent_id = parentId;
    }

Это ошибка, сгенерированная во время компиляции:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Repeated column in mapping for entity: com.vw.asa.entities.template.TdTemplates column: parent_id (should be mapped with insert="false" update="false")
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Repeated column in mapping for entity: com.vw.asa.entities.template.TdTemplates column: parent_id (should be mapped with insert="false" update="false")

Очевидно, что это имеет отношение к parent_id, имеющему более одного определения, но как мне структурировать эту сущность так, чтобы можно было выполнять следующие операции?

template.getParent().getId(); // returns parent_id
template.setParent(template); // set the parent object

Есть ли методы / свойства, которые можно удалить и которые здесь избыточны?

РЕДАКТИРОВАТЬ

Одна вещь, на которую стоит обратить внимание, это то, что я не определил окончательно шаблон проектирования для того, как родитель -детские отношения сработают.

Может оказаться, что запись oldest будет родительской, а newest - дочерней, или запись current/master/active может быть родительской, а остальные - вниз. дерево может быть ребенком жэнь. Мне еще предстоит решить, какой метод является лучшим подходом здесь.

...