在将“@Transient”应用于相应实体和加入实体后,在多对多中加入实体不被持久化

问题描述 投票:0回答:1

我设置的主要思想是通过存储库管理多对多关系。这就是为什么在下面的设置中,所有关系都被注释为

@Transient
,因为这些集合应该只“手动”填充,而不是让 Hibernate 这样做。

@Entity
@Table(name = "house")
public class House {
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private long id;

    @Transient
    private Set<Owner> owners;
}

@Entity
@Table(name = "owner")
public class Owner {
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private long id;

    @Transient
    private Set<House> houses;
}

public class HouseIdOwnerId implements Serializable {
    private long houseId;
    private long ownerId;

    public HouseIdOwnerId(final long houseId, final long ownerId) { /* ... */ }

    @Override
    public boolean equals(final Object other) { /* ... */ }
    
    @Override
    public int hashCode() { /* ... */ }
}

@Entity
@IdClass(HouseIdOwnerId.class)
@Table(name = "house_owner")
public class HouseOwner{
    @Column(name = "house_id")
    @Id
    private long houseId;

    @Column(name = "owner_id")
    @Id
    private long ownerId;

    @Transient
    private House house;

    @Transient
    private Owner owner;

    @CreatedTimestamp
    private LocalDateTime createdAt;

    public HouseOwner(final House house, final Owner owner) {
        this.houseId = house.getId();
        this.house = house;

        this.ownerId = owner.getId();
        this.owner = owner;
    }

    // ...

    @Override
    public boolean equals(final Object other) { /* ... */ }
    
    @Override
    public int hashCode() { /* ... */ } 
}

正如人们所期望的那样,当尝试持久化连接实体时,由于其属性被标记为

@Transient
,所以没有任何反应:

@Test
void testInsertRelated() {
    // ...
    this.entityManager.persist(house);
    this.entityManager.persist(owner);
    this.entityManager.persist(owner2);

    final HouseOwner ho = new HouseOwner(house, owner);
    final HouseOwner ho2 = new HouseOwner(house, owner2);

    this.entityManager.persist(ho);
    this.entityManager.persist(ho2);
}

我没有在依赖实体中做

@OneToMany
关系的原因是它们最终会以丑陋的
Set<HouseOwner> houses
Set<HouseOwner> owners
属性结束,当然在坚持主要实体时会被忽略。

所以,假设有一个请求来创建一个将与多个所有者关联的新房子。您将需要以某种方式将传入的所有者 ID 映射到多个

HouseOwner
对象,因此这些对象需要某种没有
House
部分的创建方式,因为它尚未创建。因此,你最终得到一个丑陋的
HouseOwner
对象。


总而言之,我想我在这里混淆了概念。但是,有可能做我在上面尝试的事情吗?提前谢谢你。

java hibernate join many-to-many entity
1个回答
0
投票

我不确定我是否正确理解了这个问题。为什么不使用多对多关系?是设计选择吗?让我试着用两种方式来回答。

第一部分 - 使用多对多关系

使用“多对多”关系时,不应为连接表创建实体类。在您的示例中,不应对“HouseOwner”类进行编码。您的模型包含两个实体:House 和 Owner。他们彼此交互的方式是通过多对多的关系。在映射中定义此关系后,JPA 引擎将自动派生连接表(如果默认设置不适合您,您可以使用

@JoinTable
映射)。代码看起来像这样:

@Entity
@Table(name = "house")
public class House {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @ManyToMany
    @JoinTable(name = "house_owner", joinColumns = {
        @JoinColumn(name = "house_id")},
            inverseJoinColumns = @JoinColumn(name = "owner_id"))
    private Set<Owner> owners;
}

@Entity
@Table(name = "owner")
public class Owner {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @ManyToMany(mappedBy = "owners") /* you must elect a relationship owner */
    private Set<House> houses;
}

这就是定义实体及其关系所需的全部内容。您可以看到 JPA 通过在您的

jakarta.persistence.schema-generation.scripts.action
中启用
persistence.xml
属性来期待第三个表的存在。嗅探创建的脚本,你会看到这样的东西:

create table house (id bigint generated by default as identity, primary key (id));
create table house_owner (house_id bigint not null, owner_id bigint not null, primary key (house_id, owner_id));
create table owner (id bigint generated by default as identity, primary key (id));
alter table if exists house_owner add constraint FK96rb7vss0wg6qgwkbfmt4iw9w foreign key (owner_id) references owner;
alter table if exists house_owner add constraint FKcb77jw3le78e333bx246ln3ap foreign key (house_id) references house;

第二部分 - 使用

@Transient

如果您想在建模中使用

@Transient
,我只能想象您不希望JPA 引擎为您完成艰苦的工作。但是,如果必须,您可以执行以下操作:

@Entity
@Table(name = "house")
public class House {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Transient
    private Set<Owner> owners;
}

@Entity
@Table(name = "owner")
public class Owner {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Transient
    private Set<House> houses;
}

@Entity
@Table(name = "house_owner")
public class HouseOwner {

    @Id
    @Column(name = "house_id")
    private long houseId;
    @Id
    @Column(name = "owner_id")
    private long ownerId;

    @Transient
    private House house;
    @Transient
    private Owner owner;
}

再次,通过启用

jakarta.persistence.schema-generation.scripts.action
属性嗅探创建的脚本,您会看到如下内容:

create table house (id bigint generated by default as identity, primary key (id));
create table house_owner (owner_id bigint not null, house_id bigint not null, primary key (house_id, owner_id));
create table owner (id bigint generated by default as identity, primary key (id));

如您所见,相同的三个表 - 但这次没有外键。这意味着 JPA 将忽略您的实体之间的任何关系。

© www.soinside.com 2019 - 2024. All rights reserved.