whimper
whimper

Reputation: 25

Hibernate - @ManyToOne annotation creates additional column

So I am following a tutorial about hibernate as i want to use the framework in an upcoming project. I'm having a problem with the @ManyToOne and @OneToMay annotation and Bidirectional mapping. What i want to do is very basic stuff. I simply want two tables, one reperesenting a user, and the other one representing a vehicle. Now i want the user to be able to have many vehicles and a car should "know" the user it belongs to.

As it seems to be "best practice" to create an extra table that holds the connection between users and and vehicles. I tried to do this with the @JoinTable annotation(see below) but it is not working as i want it to.

To do this, I have coded the following classes:

UserDetails.java

@Entity
@Table(name="USER_DETAILS")
public class UserDetails {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int userId;
private String userName;
private String email;
@OneToMany()
@JoinTable(name="USER_VEHICLE", joinColumns=@JoinColumn(name="USER_ID"),
            inverseJoinColumns=@JoinColumn(name="VEHICLE_ID")
)
private Collection<Vehicle> vehicle = new ArrayList<Vehicle>();

...
getters and setters

vehicle.java

@Entity
public class Vehicle {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int vehicleId;
private String vehicleName;
@ManyToOne  
private UserDetails user;

...
getters and setters

And class to test the above:

HibernateTest.Java

public class HibernateTest {
/**
 * 
 * @param args
 */
public static void main(String[] args){

    UserDetails user1 = new UserDetails();      
    user1.setUserName("testUser1");
    user1.setEmail("testEmail1");


    Vehicle vehicle1 = new Vehicle();
    vehicle1.setVehicleName("Car");

    Vehicle vehicle2 = new Vehicle();
    vehicle2.setVehicleName("Jeep");

    user1.getVehicle().add(vehicle1);
    user1.getVehicle().add(vehicle2);
    vehicle1.setUser(user1);
    vehicle2.setUser(user1);    

    SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
    Session session = sessionFactory.openSession();
    session.beginTransaction();
    session.save(user1);
    session.save(vehicle1);
    session.save(vehicle2);
    session.getTransaction().commit();
    session.close();

When I run this, it executes without any errors or exceptions and it creates the following tables:

USER_DETAILS
+------+----------+---------+
|userId|email     |userName |
+------+----------+---------+
|1     |testEmail1|testUser1|
+------+----------+---------+

VEHICLE
+---------+-----------+-----------+
|vehicleId|vehicleName|user_userId| <- did not expect this column
+---------+-----------+-----------+
|1        |Car        |1          |
+---------+-----------+-----------+
|2        |Jeep       |1          |
+---------+-----------+-----------+

USER_VEHICLE
 +------+----------+
|USER_ID|VEHICLE_ID|
+-------+----------+
|1      |1         |
+-------+----------+
|1      |2         |
+-------+----------+

As I understand it, the additional column "user_userId" that was created by hibernate seems to be unnecessary, as the connection between users and vehicles is already represented in the "USER_VEHICLE" table, and I did not intend to have this additional column created.

Is the way I did the bidirectional mapping wrong? And what is the right way to get this to work without the additional column being created?

Upvotes: 1

Views: 1210

Answers (3)

jabu.10245
jabu.10245

Reputation: 1892

@JoinTable is necessary if you want a @ManyToMany relationship.

@Entity
public class UserDetails {
    /* ... */

    @ManyToMany
    @JoinTable(name = "user_vehicle",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "vehicle_id"))
    private List<Vehicle> vehicles;
}

@Entity
public class Vehicle {
    /* ... */
}
USER_DETAILS      VEHICLE           USER_VEHICLE
+---------+       +------------+    +---------+------------+
| user_id |       | vehicle_id |    | user_id | vehicle_id |
+---------+       +------------+    +---------+------------+
|       1 |       |          1 |    |       1 |          1 |
+---------+       +------------+    +---------+------------+

Since you don't want that, you can just remove the @JoinTable like so:

@Entity
public class UserDetails {
    /* ... */

    @OneToMany(mappedBy = "user")
    private List<Vehicle> vehicles;
}

@Entity
public class Vehicle {
    /* ... */

    @ManyToOne
    private UserDetails user;
}
USER_DETAILS      VEHICLE       
+---------+       +------------+---------+
| user_id |       | vehicle_id | user_id |
+---------+       +------------+---------+
|       1 |       |          1 |       1 |
+---------+       +------------+---------+

You only need a third table if you want to store additional data for a (UserDetails, Vehicle) tuple, in which case you would create a third class.

@Entity
public class UserDetails {
    /* ... */

    @OneToMany(mappedBy = "user")
    private List<UserVehicle> vehicles;
}

@Entity
public class Vehicle {
    /* ... */
}

@Entity
public class UserVehicle {
    /* ... */

    @ManyToOne
    private UserDetails user;

    @ManyToOne
    private Vehicle vehicle;

    @Basic
    private String someString;
}
USER_DETAILS      VEHICLE           USER_VEHICLE
+---------+       +------------+    +---------+------------+-------------+
| user_id |       | vehicle_id |    | user_id | vehicle_id | some_string |
+---------+       +------------+    +---------+------------+-------------+
|       1 |       |          1 |    |       1 |          1 |  Hello      |
+---------+       +------------+    +---------+------------+-------------+

Upvotes: 1

Pedro Martins PT
Pedro Martins PT

Reputation: 1

It is normal that the column is generated. The side of the Many on a database relation have to save the FK value.

Try to remove your @Join annotation... Just @OneToMany

Upvotes: 0

VDanyliuk
VDanyliuk

Reputation: 1049

Try to specify relations in Vehicle side and in User side use mapedBy property

Upvotes: 0

Related Questions