gpt4 book ai didi

java - JPA Hibernate删除实体的子对象,与双PK触发SQL更新而不是删除连接?

转载 作者:行者123 更新时间:2023-12-01 17:41:39 28 4
gpt4 key购买 nike

我有以下表结构:

enter image description here

  • 每个 chat_bot 可以有多个版本。
  • 每个版本都可以部署到环境中。
  • 版本具有双主键,其中之一是从 chat_bot 表引用的。
  • 环境表只有主键。其中两个是从版本表中引用的。

我有以下类结构:

@Entity
@AllArgsConstructor
@Table(name = "chat_bot")
@NoArgsConstructor
public class Bot {

@Id
private String id;

@LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(mappedBy = "botId", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<BotVersion> versions = new LinkedHashSet<>();
}

@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class BotVersionPK implements Serializable {
private String botId;
private int version;
}


@Entity
@AllArgsConstructor
@Table(name = "chat_bot_version")
@NoArgsConstructor
@IdClass(BotVersionPK.class)
public class BotVersion {

@Id
private String botId;
@Id
private int version;

@Type(type = "text")
private String json;

@OneToMany(fetch = FetchType.LAZY, orphanRemoval = true)
@JoinColumns({
@JoinColumn(name = "botId", referencedColumnName = "botId"),
@JoinColumn(name = "version", referencedColumnName = "version")
})
private Set<BotEnvironments> environments = new LinkedHashSet<>();
}

@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class BotEnvironmentsPK implements Serializable {
private String botId;
private int version;
private String environmentCode;
}

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "chat_bot_environments")
@IdClass(BotEnvironmentsPK.class)
public class BotEnvironments {
@Id
private String botId;
@Id
private int version;
@Id
private String environmentCode;
}

我使用 JpaRepository< Bot, String > 来加载和保存信息。

问题:如果我从“环境”集中删除一个项目并将其保留,Hibernate 不会触发 DELETE 操作,而是触发 UPDATE 操作:

update chat_bot_environments set bot_id=null, version=null where bot_id=? and version=?

我收到以下错误,该错误是有效的:

Column 'bot_id' cannot be null

为什么 Hibernate JPA 触发器更新而不是删除?如何删除通过非空 PK 连接的子元素?

最佳答案

您的映射存在一些错误。

  1. 连接列始终位于子端:

    @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true)
    @JoinColumns({
    @JoinColumn(name = "botId", referencedColumnName = "botId"),
    @JoinColumn(name = "version", referencedColumnName = "version")
    })
    private Set<BotEnvironments> environments = new LinkedHashSet<>();

此映射应移至子级 (BotEnvironments)。

  • mappedBy 应指向与实体相同类型的字段。您已定义 mappedBy = "botId",但 botId 的类型为 String(它是外键)。这不会映射实体之间的关系。

  • 不要害怕双向关系。它们不会造成性能开销 - 实际上它们通常可以优化持久性性能。

  • 我还纠正了其他一些小问题。为了简洁起见,我省略了 Lombok 注释和获取类型。这是正确的映射(生成的结果数据库架构是相同的):

    机器人:

    @Entity
    @Table(name = "chat_bot")
    public class Bot {

    @Id
    private String id;

    @OneToMany(mappedBy = "bot", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<BotVersion> versions = new LinkedHashSet<>();

    }

    机器人版本:

    @Entity
    @Table(name = "chat_bot_version")
    @IdClass(BotVersionPK.class)
    public class BotVersion {

    @Id
    private String botId;
    @Id
    private int version;

    @ManyToOne
    @JoinColumn(name = "botId", insertable=false, updatable=false)
    private Bot bot;

    @Type(type = "text")
    private String json;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "botVersion")
    private Set<BotEnvironments> environments = new LinkedHashSet<>();

    }

    机器人环境:

    @Entity
    @Table(name = "chat_bot_environments")
    @IdClass(BotEnvironmentsPK.class)
    public class BotEnvironments {
    @Id
    private String botId;
    @Id
    private int version;
    @Id
    private String environmentCode;

    @ManyToOne
    @JoinColumns({
    @JoinColumn(name = "botId", referencedColumnName = "botId", insertable=false, updatable=false),
    @JoinColumn(name = "version", referencedColumnName = "version", insertable=false, updatable=false)
    })
    private BotVersion botVersion;

    }

    Id 类未更改。

    这是一个简单的测试,用于检查其是否有效:

    @Test
    public void test() {
    // given
    BotEnvironments botEnvironments = new BotEnvironments("bid", 1, "env");
    BotEnvironments botEnvironments1 = new BotEnvironments("bid", 1, "env1");
    BotVersion botVersion = new BotVersion("bid", 1, "json", Set.of(botEnvironments, botEnvironments1));
    Bot bot = new Bot("bid", Set.of(botVersion));
    botRepository.save(bot);

    // when
    Bot savedBot = botRepository.findAll().get(0);
    savedBot.getVersions().iterator().next().getEnvironments().remove(savedBot.getVersions().iterator().next().getEnvironments().iterator().next());
    botRepository.save(savedBot);

    // then
    assertEquals(1, botEnvironmentsRepository.findAll().size());
    }

    关于java - JPA Hibernate删除实体的子对象,与双PK触发SQL更新而不是删除连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60340808/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com