如何正确管理 jpa 双向关系?

how to manage jpa bidirectional relation ships correctly?

我正在使用 EJB3.2 和 JPA 2.1。 在我的应用程序中,我有这些实体(简而言之):

@Entity
public class Festival
{
    int Id;
    String name;
    ...
    @ManyToOne
    @JoinColumn(name = "merchant", referencedColumnName = "Id")
    Merchant merchant;
}

@Entity
public class Merchant
{
    int Id;
    String name;

    ...

    @ManyToOne
    @JoinColumn(name = "category", referencedColumnName = "Id")
    Category category;

    @ManyToOne
    @JoinColumn(name = "city", referencedColumnName = "Id")
    City city;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "festival")
    List<Festival> festivalList;
}

@Entity
public class Category
{
    int Id;
    String name;
    ...
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "merchant")
    List<Merchant> merchantList;
}

@Entity
public class City
{
    int Id;
    String name;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "merchant")
    List<Merchant> merchantList;
}

因此,(Festival, Merchant) 具有双向关系,例如 (Merchant, Category) 和 (Merchant, City)

问题是当我删除或更改商家时,类别 merchantList 和城市 merchantList 中仍然有一个未更改的副本!等等..

我应该如何管理这些变化?!为什么 JPA 不对它自己的其他副本进行更改?这不是增加了错误副本的风险吗?!

我认为 Christian Bauer 和 Gavin King 的 "Java Persistence With Hibernate"(第 261 页)中的这句话可能对您有用:

Contrary to EJB 2.0 CMR, Hibernate and JPA associations are all inherently unidirectional.

所以商户到品类的关联不同于品类到商户的关联,需要分开管理。

编辑: 我调整了您的初始 bean 配置以使其看起来应该如此: (当然,你会使用合适的主键生成策略。)

@Entity
public class Festival
{
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    int Id;
    String name;

    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name = "merchant")
    Merchant merchant;
}
@Entity
public class Merchant
{
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    int Id;
    String name;

    @ManyToOne
    @JoinColumn(name = "category")
    Category category;

    @ManyToOne
    @JoinColumn(name = "city")
    City city;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "merchant")
    List<Festival> festivalList;
}
@Entity
public class Category
{
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    int Id;
    String name;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "category")
    List<Merchant> merchantList;
}
@Entity
public class City
{
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    int Id;
    String name;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "city")
    List<Merchant> merchantList;
}

确保在调用 categories.getMerchantList() 之前坚持(商家)。

JPA 将您的实体视为常规 java 对象,并且不会为您维护关系 - 应用程序负责确保双向关系的双方在您更改一侧时保持同步。因此,当您从商户中取消对城市的引用时,您必须从城市的 merchantList 中删除对商户的引用,然后在必要时合并。

否则,在从数据库中刷新对象之前,您通过 java 对象查看的数据将与数据库不同步。您可以权衡保持双方同步或在需要时刷新甚至不映射非拥有方的价值和成本,并在逐个实体的基础上确定什么对您的应用程序更好。