Simon Plangger
Simon Plangger

Reputation: 247

Saving entities fetched from a query with hibernate

I hava a basic Hibernate/JPA question. I want to find a best practice solution for saving entities. I have a List of Entities and many of them might be altered so I want to save them all at once.

I believe everything is pretty much standard. (Just example code for readability reasons)

Entity: Car

@Entity
public class Car implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    private id;

    private String model;

    // .... Setter

    // .... Getter

}

Service Class: 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? */
    }
}

Controller: 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);
        }
    }
}

I found quite a few ways of saving the entity. The obvious are entityManager.merge(car) for existing entities and entityManager.persist(car) for new ones. In theory thats easy but how do I know which entity is new?

The documentation suggests entityManager.flush(), which in theory updates all existing and inserts all new entities. It works but only if I fetch the entity with find().

The Question:

I want to fetch all entities in one step, add new ones and then save them all in one methode (btn_saveClick()). How is this task best accomplished?

Upvotes: 2

Views: 2578

Answers (3)

Firo
Firo

Reputation: 30813

I'm not familiar with JPA but in hibernate there is session.saveOrUpdate()

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

Update:

As i understand JPA, its merge is like session.merge which is totally different as it doesn't track changes to object supplied to it while persist/save/update/saveOrUpdate would track subsequent changes to car, leading to subtle differences

Update:

since you use the same entitymanager it should suffice to

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

without the subtle difference of persist and merge

Upvotes: 2

BalusC
BalusC

Reputation: 1108722

Just check if the @Id is been set.

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

More common approach, however, is to offer separate create() and update() service methods.

Upvotes: 2

Alex Barnes
Alex Barnes

Reputation: 7218

The flush operation will operate on all entities in the current Hibernate session - new entities are inserted and existing entities are updated if they have changed.

You need to ensure that all entities are attached to the session. You do this by using merge as you correctly say. After you have loaded all of the entities the session is closed when the transaction ends. Your objects are then in a detached state i.e. have been persisted but are no longer attached to a session.

I would amend your logic so that your carService#save takes a List. It can then call merge on each one (attaching them to the session). Then when your transaction ends Hibernate will flush all changes to the database at once.

Upvotes: 1

Related Questions