休眠:加入带有额外列的表,从一侧删除子项

Posted

技术标签:

【中文标题】休眠:加入带有额外列的表,从一侧删除子项【英文标题】:Hibernate: Join table with extra columns, remove children from one side 【发布时间】:2016-10-13 13:50:18 【问题描述】:

场景如下

我有 2 个表,Company 和 Activity。一家公司可以有一项或多项活动。其中一项活动是“主要”活动,所有其他活动都成为次要活动。

为了处理这个问题,我为连接表创建了 2 个实体(Activity、Company)和第三个实体,即 CompanyActivity

我以this tutorial为起点

在我的代码下方(省略了 getter 和 setter)

Company.java

@Entity
@Table(name = "T_COMPANY")
public class Company 

    @Id
    @Column(name = "COM_ID")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "company")
    private List<CompanyActivity> activities = new ArrayList<>();

Activity.java

@Entity
@Table(name = "T_ACTIVITY")
public class Activity 

    @Id
    @Column(name = "ACT_ID")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String code;

    private String description;

    private boolean availableOnline;

CompanyActivity.java

@Entity
@Table(name = "T_COMPANY_ACTIVITY")
public class CompanyActivity 

    @Id
    @Column(name = "COM_ACT_ID")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "COM_ID")
    private Company company;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "ACT_ID")
    private Activity activity;

    private boolean primary;


为公司添加活动没有问题。 children 集合包含新添加的活动,并且总是有一个按预期标记为 primary

更新公司时会出现问题。

当我添加一个新活动时,所有以前的现有活动都会再次保留。 当我删除一个活动时,它并没有从表中删除。

我正在使用此代码更新公司的活动

    company.getActivities().clear();
    company.getActivities().addAll(newActivities);

    company = repository.save(company);

在这段代码中,newActivities 有应该考虑的新活动(这个集合没有以前的,我只是将它们全部替换)

我尝试将orphanRemoval=true 添加到公司上的@OneToMany(cascade = CascadeType.ALL, mappedBy = "company"),但是当没有其他公司使用它时,这会删除活动类型,这是错误的,因为它们应该始终可用。

您能帮我在Company 上同步activities 集合而不从Activity 表中删除元素吗?

非常感谢!

【问题讨论】:

【参考方案1】:

我解决了。以下是我遵循的步骤。

首先,我将我的 Join 表实体级联类型更改如下

@Entity
@Table(name = "T_COMPANY_ACTIVITY")
public class CompanyActivity 

    @Id
    @Column(name = "COM_ACT_ID")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne(cascade = CascadeType.PERSIST, CascadeType.MERGE)
    @JoinColumn(name = "COM_ID")
    private Company company;

    @ManyToOne(cascade = CascadeType.PERSIST, CascadeType.MERGE)
    @JoinColumn(name = "ACT_ID")
    private Activity activity;

    private boolean primary;


然后,我再次将“orphanRemoval”属性添加到公司映射中,并更改了我的 CascadeTypes,如下所示

@OneToMany(cascade = CascadeType.PERSIST, CascadeType.MERGE, mappedBy = "empresa", orphanRemoval = true)
private List<CompanyActivity> activities = new ArrayList<>();

通过这些更改,我的映射使用我用来替换关系的相同代码按预期工作。

company.getActivities().clear();
company.getActivities().addAll(newActivities);

company = repository.save(company);

谢谢:)

【讨论】:

【参考方案2】:

您创建实体的方式不正确。您无需为连接表 (CompanyActivity/T_COMPANY_ACTIVITY) 创建实体。相反,您应该在活动实体上使用 @JoinTable。如下所示:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "company")
@JoinTable(
    name = "T_COMPANY_ACTIVITY",
    joinColumns = @JoinColumn(name = "COM_ID"),
    inverseJoinColumns = @JoinColumn(name = "ACT_ID")
)
private List<CompanyActivity> activities = new ArrayList<>();

有关连接表的一对多/多对一如何工作的更详细说明:http://www.codejava.net/frameworks/hibernate/hibernate-one-to-many-association-on-join-table-annotations-example

【讨论】:

我需要为关系添加一个布尔属性。如果您查看 CompanyActivity,我添加了一个布尔值“主要”,用于确定公司的主要活动。用你描述的方法,我做不到。

以上是关于休眠:加入带有额外列的表,从一侧删除子项的主要内容,如果未能解决你的问题,请参考以下文章

使用重复的额外列使多对多休眠

无法使用休眠删除将集合作为子项的实体

休眠标准组结果按日期从时间戳

休眠一对多关联删除

在 postgresql 中使用休眠注释设置列的默认值

如何在休眠中指定双精度?