78

Maybe this is a stupid question but it's bugging me.

I have a bi-directional one to many relationship of Employee to Vehicles. When I persist an Employee in the database for the first time (i.e. it has no assigned ID) I also want its associated Vehicles to be persisted.

This works fine for me at the moment, except that my saved Vehicle entity is not getting the associated Employee mapped automatically, and in the database the employee_id foreign key column in the Vehicle table is null.

My question is, is it possible to have the Vehicle's employee persisted at the same time the Employee itself is being persisted? I realise that the Employee would need to be saved first, then the Vehicle saved afterwards. Can JPA do this automatically for me? Or do I have to do something like the following:

Vehicle vehicle1 = new Vehicle();
Set<Vehicle> vehicles = new HashSet<Vehicle>();
vehicles.add(vehicle1);

Employee newEmployee = new Employee("matt");
newEmployee.setVehicles(vehicles);
Employee savedEmployee = employeeDao.persistOrMerge(newEmployee);

vehicle1.setAssociatedEmployee(savedEmployee);
vehicleDao.persistOrMerge(vehicle1);

Thanks!

Edit: As requested, here's my mappings (without all the other methods etc.)

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="employee_id")
    private Long id;

    @OneToMany(mappedBy="associatedEmployee", cascade=CascadeType.ALL)
    private Set<Vehicle> vehicles;

    ...

}

@Entity 
public class Vehicle {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="vehicle_id")
    private Long id;

    @ManyToOne
    @JoinColumn(name="employee_id")
    private Employee associatedEmployee;

    ...
}

I just realised I should have had the following method defined on my Employee class:

public void addVehicle(Vehicle vehicle) {
    vehicle.setAssociatedEmployee(this);
    vehicles.add(vehicle);
}

Now the code above will look like this:

Vehicle vehicle1 = new Vehicle();

Employee newEmployee = new Employee("matt");
newEmployee.addVehicle(vehicle1);
Employee savedEmployee = employeeDao.persistOrMerge(newEmployee);

Much simpler and cleaner. Thanks for your help everyone!

JMM
  • 3,922
  • 6
  • 39
  • 46

2 Answers2

59

You have to set the associatedEmployee on the Vehicle before persisting the Employee.

Employee newEmployee = new Employee("matt");
vehicle1.setAssociatedEmployee(newEmployee);
vehicles.add(vehicle1);

newEmployee.setVehicles(vehicles);

Employee savedEmployee = employeeDao.persistOrMerge(newEmployee);
Shay Elkayam
  • 4,128
  • 1
  • 22
  • 19
Bobby
  • 1,571
  • 14
  • 15
  • 3
    Ooh, ok. That works. But I thought there might be a way where I don't have to explicity set the associated employee on the vehicle? – JMM Nov 25 '09 at 12:10
  • I don't think that is possible with JPA. I have also used Hibernate and there if I remember correctly that is possible. – Bobby Nov 25 '09 at 12:16
  • Thanks for pointing out the problem in my original code, I've updated it with how I'm going to solve it. – JMM Nov 25 '09 at 12:33
  • YOU RULE man... Great solution... I had this problem for days.. I have thought this solution myself but wasnt logical to me – GorillaApe May 07 '10 at 16:56
  • 4
    The answer is not complete. You still need to set cascade due to ```By default no operations are cascaded.``` – petertc Jun 14 '16 at 09:44
32

One way to do that is to set the cascade option on you "One" side of relationship:

class Employee {
   // 

   @OneToMany(cascade = {CascadeType.PERSIST})
   private Set<Vehicles> vehicles = new HashSet<Vehicles>();

   //
}

by this, when you call

Employee savedEmployee = employeeDao.persistOrMerge(newEmployee);

it will save the vehicles too.

buræquete
  • 14,226
  • 4
  • 44
  • 89
user218435
  • 321
  • 2
  • 2
  • Hi, thanks for the reply. I do have the cascade set where you've suggested and the vehicles do get saved. My problem is that when the vehicles are saved, I want their foreign key column employee_id to contain the id of the employee I just saved. – JMM Nov 25 '09 at 09:42
  • 1
    The foreign key is supposed to be saved in the cascade... could you send the @OneToMany and @ManyToOne annotations that you are using for checking? Best Regards Denes – user218435 Nov 25 '09 at 11:45
  • 10
    Hi, The problem is because of the mappedBy attribute, which defines the owner of the relation as the Many side. That´s the way that is supposed to be in bidirecional One to Many Relationships, but it´s possible to change so the owner will be the One side as you intended. This link, section 2.2.5.3.2.1 has a sample how to do it. http://docs.jboss.org/hibernate/stable/annotations/reference/en/html/entity.html Best Regards Denes – user218435 Nov 25 '09 at 17:00