java - 在 Spring Data JPA 中保留两个不同模式之间具有父子关系的表

标签 java sql-server hibernate spring-data-jpa jpa-2.0

我正在努力,

ChildTable child = new ChildTable();
clild.setParentTwoID(prentTwoID);
ParentOne parentOne = new ParentOne();
parentOne.getChildTableList().add(childTable);
parentReposetory.save(parentOne);

其中,ParentOne 在 schema S1 中,而 ParentTwo 和 ChildTable 在 schema S2 中。

ParentOne.java

@Data
@EqualsAndHashCode(callSuper = false)
@Entity
@Table(name = "ParentOne", schema = "S1")
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, scope = ParentOne.class)
public class ParentOne implements Serializable {

    private static final long serialVersionUID = 7502273069461829133L;

    @Id
    @Column(name = "ParentOneID", unique = true, nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer parentOneID;

    @OneToMany(targetEntity = ChildTable.class, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "ParentOneID", nullable = false, insertable = false, updatable = false)
    private List<ChildTable> childTableList;
}

ParentTwo.java

@Data
@EqualsAndHashCode(callSuper = false)
@Entity
@Table(name = "ParentTwo", schema = "S2")
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, scope = ParentTwo.class)
public class ParentTwo implements Serializable {

    private static final long serialVersionUID = 7502273069461829133L;

    @Id
    @Column(name = "ParentTwoID", unique = true, nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer parentTwoID;

    @OneToMany(targetEntity = ChildTable.class, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "ParentTwoID", nullable = false, insertable = false, updatable = false)
    private List<ChildTable> childTableList;
}

ChildTable.java

@Data
@EqualsAndHashCode(callSuper = false)
@Entity
@Table(name = "ChildTable", schema = "S2")
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, scope = ChildTable.class)
public class ChildTable implements Serializable {

    private static final long serialVersionUID = -6331600489988183852L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ChildTableID", unique = true, nullable = false)
    private Integer childTableID;

    @Column(name = "ParentOneID")
    private Integer parentOneID;

    @Column(name = "ParentTwoID", nullable = false)
    @NotNull(message = "mandatory_field")
    private Integer parentTwoID;

}

这里 ParentTwo 已经存在并且我有它的 Id。我将只保留 ParentOne 以及不同架构的 ChildTable。当我这样做时,我会收到错误提示。

rg.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement

Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Cannot insert the value NULL into column 'ParentOneID', table 'PT_Sample.S2.ChildTable'; column does not allow nulls. INSERT fails.

SQL Error: 515, SQLState: 23000

最佳答案

使用 JPA 时,需要允许 JPA 提供者管理实体实例之间的关系。在给定的情况下,通过跟踪各种外键标识符来手动管理关系。因此,JPA 提供程序无法设置外键列值。

基本问题似乎在于理解 JPA(或任何其他 ORM)的工作原理。实体不是数据库表的逐列副本。需要将它们视为对象并建模为对象,而无需考虑底层数据库。实体属性到数据库列的映射应留给 JPA 提供程序。


以下实体模型将解决该问题(为简洁起见,删除了所有不必要的代码):

ParentOne entity

@Entity
@Table(name="ParentOne", schema="S1")
public class ParentOne {
  @Id
  @Column(name="ParentOneID", unique=true, nullable=false)
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL, mappedBy="parentOne")
  private List<Child> children;

  public void addChild(final Child child) {
    if (children == null) {
      children = new ArrayList<>();
    }

    children.add(child);

    child.setParentOne(this);
  }
}

以下几点值得注意:

  1. 模式名称 (S1) 已与实体实例必须持久保存到的表名称一起声明。
  2. 与子实体的关系声明为一个集合,并注解为@OneToMany
  3. 持久性操作(保存、更新、删除)级联到子实体实例 (cascade = CascadeType.ALL)。这可确保对父实例的持久性操作自动处理对任何关联子实例的适当操作。

ParentTwo entity

@Entity
@Table(name="ParentTwo", schema="S2")
public class ParentTwo {
  @Id
  @Column(name="ParentTwoID", unique=true, nullable=false)
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL, mappedBy="parentTwo")
  private List<Child> children;

  public void addChild(final Child child) {
    if (children == null) {
      children = new ArrayList<>();
    }

    children.add(child);

    child.setParentTwo(this);
  }
}

Child entity

@Entity
@Table(name="ChildTable", schema="S2")
public class Child {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name="ChildTableID", unique=true, nullable=false)
  private Integer id;

  @ManyToOne(cascade=CascadeType.PERSIST)
  @JoinColumn(name="ParentOneID", nullable=false)
  private ParentOne parentOne;

  @ManyToOne(cascade=CascadeType.PERSIST)
  @JoinColumn(name="ParentTwoID", nullable=false)
  private ParentTwo parentTwo;

  void setParentOne(final ParentOne parentOne) {
    this.parentOne = parentOne;
  }

  void setParentTwo(final ParentTwo parentTwo) {
    this.parentTwo = parentTwo;
  }
}

以下几点值得注意:

  1. 架构名称 (S2) 与表名称一起声明。
  2. 与父表的关联声明为对象实例,而不是原始列。

在此之后,以下代码将正常工作:

Child child = new Child();
...

ParentOne parentOne = new ParentOne();
ParentTwo parentTwo = new ParentTwo();
...

parentOne.addChild(child);
parentTwo.addChild(child);

parentOneRepository.save(parentOne);

关于java - 在 Spring Data JPA 中保留两个不同模式之间具有父子关系的表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43716896/

相关文章:

java - 在 IA 32 位平台上使用 JUSBPMP : NetBeansProjects\JUsbPmP\libjpmp-0. 1.1.so : Can't load this . dll(机器代码 = 0x101)时出错

mysql - 尝试绑定(bind)参数号 0。SQL Server 最多支持 2100 个参数

java - Hibernate:从连接表中删除孤立表

java - 如何在java中确定数据库表列的大小

java - 无法使用 Spring 在 Junit 测试中注入(inject) DAO

java - 使用 Hibernate 注释的惰性一对一可选双向映射

java - 使用 0 到另一个 java 类中的多个对象初始化对象

Java接口(interface): compiler error

java - 没有通过 jax ws 生成 java 工件

sql - 查询性能、索引和预测所覆盖索引的写入时间性能影响?