【问题标题】:Saving entities fetched from a query with hibernate使用休眠保存从查询中获取的实体
【发布时间】:2012-03-12 16:27:42
【问题描述】:

我有一个基本的 Hibernate/JPA 问题。我想找到保存实体的最佳实践解决方案。我有一个实体列表,其中许多可能会被更改,所以我想一次保存它们。

我相信一切都非常标准。 (出于可读性原因,只是示例代码)

实体:汽车

@Entity
public class Car implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    private id;

    private String model;

    // .... Setter

    // .... Getter

}

服务类别:CarService

@Named
@Transactional
public class CarServiceImpl implements CarService {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List<Car> findAll() {
        TypedQuery<Car> q = entityManager.createQuery(
                "FROM Car", Car.class);
        return q.getResultList();
    }

    @Override
    public void saveEntity (Car car) {
        /* What exactly am I doing here? */
    }
}

控制器:CarEditController

@Named
public class CarEditController implements Serializable {

    private static final long serialVersionUID = 1L;

    @Inject
    private CarService carService;

    private List<Car> cars;

    public List<Car> getCars () {
        return carService.findAll();
    }

    public void setCars (List<Car> cars) {
        this.cars = cars;
    }

    public void btn_newClick() {
        Car newCar = new Car();
        car setModel("BMW");

        cars.add(newCar);
    }

    public void btn_saveClick() {
        for (Car car : cars) {
            carService.saveEntity(car);
        }
    }
}

我发现了很多保存实体的方法。显而易见的是 entityManager.merge(car) 用于现有实体,entityManager.persist(car) 用于新实体。理论上这很容易,但我怎么知道哪个实体是新的?

documentation 建议 entityManager.flush(),理论上它会更新所有现有实体并插入所有新实体。它有效,但前提是我使用 find() 获取实体。

问题:

我想一步获取所有实体,添加新实体,然后将它们全部保存在一个方法中 (btn_saveClick())。如何最好地完成这项任务?

【问题讨论】:

    标签: java hibernate jpa


    【解决方案1】:

    我不熟悉 JPA,但在休眠中有 session.saveOrUpdate()

    for(Car car : existingAndNewCars)
    {
        session.saveOrUpdate(car);
    }
    

    更新:

    据我了解 JPA,它的 merge 就像 session.merge 完全不同,因为它不跟踪提供给它的对象的更改,而 persist/save/update/saveOrUpdate 会跟踪汽车的后续变化,导致细微的差异

    更新:

    由于您使用相同的实体管理器,它应该就足够了

    @Override
    public void saveEntity (Car car) {
        if (car.getId() == null) {
            entityManager.persist(car);
    }
    

    没有persist和merge的细微差别

    【讨论】:

    • OP 使用的是 JPA 实现的 Hibernate 4.x,而不是黑暗 J2EE 时代的“Good Ol”Hibernate 3.x。
    • @BalusC 如果我必须在 H 4.x 中自己实现 SaveOrUpdate,那么我对“Good Ol”Hibernate 3.x 和 NHibernate 3.x 更满意
    • 那很好:) 我根本没有争论这个。我只是警告说 OP 没有使用 Hibernate 3.x,因此这个答案根本不适用于具体问题。
    • @BalusC 只是评论“从黑暗的 J2EE 时代回来”,这对我来说意味着“不如今天”:)
    • 哦 :) 承认,Java EE 5 with JPA 是在 2006 年半推出的,也就是 6 年前。六年!自 Java EE 6 于 2009 年底推出以来,J2EE 也已过时。那几乎是 2.5 年前。
    【解决方案2】:

    只需检查@Id 是否已设置。

    @Override
    public void saveEntity (Car car) {
        if (car.getId() == null) {
            entityManager.persist(car);
        } else {
            entityManager.merge(car);
        }
    }
    

    然而,更常见的方法是提供单独的 create()update() 服务方法。

    【讨论】:

    • 你是对的。之前应该可以保存,但是主键的定义有问题。在 real life 项目中,我使用复合标识符,这一直是个问题。谢谢!
    【解决方案3】:

    刷新操作将对当前 Hibernate 会话中的所有实体进行操作 - 插入新实体并更新现有实体(如果它们已更改)。

    您需要确保所有实体都附加到会话。正如您正确所说的那样,您可以通过使用合并来做到这一点。加载所有实体后,事务结束时会话关闭。然后,您的对象处于分离状态,即已持久化但不再附加到会话。

    我会修改您的逻辑,以便您的 carService#save 获取一个列表。然后它可以对每个调用合并(将它们附加到会话)。然后,当您的事务结束时,Hibernate 将立即将所有更改刷新到数据库。

    【讨论】:

    • 感谢您的信息。这似乎是正确的做法。我从来不知道 merge() 做了什么以及为什么在我使用它时会保存实体。
    猜你喜欢
    • 2012-09-09
    • 2016-12-27
    • 2020-12-06
    • 2013-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-30
    相关资源
    最近更新 更多