spring-数据:外键为主

spring-data: foreign-key as a primary

我有一个包含 100 个字段的 table,我想将其分成 3-4 个 table。创建时,table 之一的主键将成为剩余 table 的外键和主键。

我试过这样的东西

@Entity
public class Entity1 implements Serializable {
    @Id
    @Column(name = "id")
    private String id;
    
    ...
}

@Entity
@IdClass(Entity1.class)
public class Entity2 implements Serializable {
    @Id
    @OneToOne
    @JoinColumn(name = "id",  referencedColumnName = "id")
    private Entity1 id;
    
    ...
}


@Repository
public interface Entity1Repository extends JpaRepository<Entity1, String> {
    Optional<Entity1> findById(String id);
}

@Repository
public interface Entity2Repository extends JpaRepository<Entity2, Entity1> {
    Optional<Entity2> findById(Entity1 id);
}

它正在创建 tables,但给出错误 This class [class xyz.Entity2] 没有定义 IdClass

还查看了一些参考资料,例如 @MapsId 的使用。但是没有一个解决方案对我有用。有任何输入吗?

谢谢

文卡塔马杜

我不知道您在使用 MapsId 功能时尝试了哪​​种方法。但在这种情况下它肯定可以帮助你。以下是 MapsId 实现的示例代码:

@Entity
public class Entity1 implements Serializable {
    @Id
    private Long id;
    private String name;

    @OneToOne(mappedBy = "entity1")
    private Entity2 entity2;

    @OneToOne(mappedBy = "entity1")
    private Entity3 entity3;
}

这是 parent class,它将只保存 OneToOne 关联的引用。 child 将成为关系的所有者。

这是你的 Entity2 child:

@Entity
public class Entity2 implements Serializable {
    @Id
    private Long id;
    private String value;

    @MapsId
    @OneToOne(cascade = CascadeType.PERSIST)
    @JoinColumn(name = "id")
    private Entity1 entity1;
}

正如您所说,您会将主要实体拼接成多个 child 我继续使用另一个 child 实体来阐明我的观点:

@Entity
public class Entity3 implements Serializable {
    @Id
    private Long id;
    private String value;

   @MapsId
   @OneToOne(cascade = CascadeType.PERSIST)
   @JoinColumn(name = "id")
   private Entity1 entity1;
}

你现在可能已经注意到我正在使用:

  1. @JoinColumn child classes 中的注解告诉 hibernate 使用 child 的 id 列将此 OneToOne 关系映射到 Entity1 class.
  2. 我在 child classes 中使用 cascadeType = PERSIST。

第一步需要做id的关系映射。第二步需要在同一事务中将所有 3 个实体保存到数据库中。稍后会详细介绍。

Let's see how you can now save all of these entities into the database.

@Transactional
public void saveEntities() {
    Long id = 1L;
    Entity1 entity1 = new Entity1();
    entity1.setId(id);
    entity1.setName("Test1Entity1: " + id);

    Entity2 entity2 = new Entity2();
    entity2.setValue("entity2Value: " + id);
    entity2.setEntity1(entity1);
    entity2Repository.save(entity2);
    Entity3 entity3 = new Entity3();
    entity3.setValue("Test3Entity:" + id);
    entity3.setEntity1(entity1);
    entity3Repository.save(entity3);
}

请注意,我没有将 Entity1 class 保存到存储库中。它由我传递给 OneToOne 注释操作的 cascadeType=PERSIST 参数保存。

This should be able to save all the entities along with the parent one.

注意: 之前我说过 cascadeType=PERSIST 以及为什么它在这里很重要。如果您不使用它,那么您必须首先显式调用 Entity1 存储库方法以将其 object 保存到数据库,然后您可以将它们设置到 child 实体中。但是如果你这样做,当你对 child 实体执行保存操作时,hibernate 会抛出:a different object with the same identifier value was already associated with the session 异常。

尝试使用 @PrimaryKeyJoinColumn:

@Entity
public class Entity1 {
    @Id
    @Column(name = "id")
    private String id;
    
    ...

    @OneToOne(mappedBy = "entity1")
    @PrimaryKeyJoinColumn
    private Entity2 entity2;
}

@Entity
public class Entity2 {
    @Id
    @Column(name = "entity1_id")
    private String id;
    
    ...

    @MapsId
    @OneToOne(cascade = CascadeType.PERSIST)
    @JoinColumn(name = "entity1_id)
    private Entity1 entity1;
}

public interface Entity2Repository extends JpaRepository<Entity2, String>

测试:

@Test
void save() {
    Entity1 entity1 = new Entity1();
    entity1.setId("iddddd");

    Entity2 entity2 = new Entity2();
    detail.setEntity1(entity1);

    this.entity2Repository.save(entity2);
}

参考Shared Primary Key