Sriram Sridharan
Sriram Sridharan

Reputation: 740

JPA Hibernate map more than 2 entities

I want to map my entities in the following manner:

I have a User and he buys a Car (a specific brand, model and variant).

To do this, I have created the following classes.

Car.java

@Entity
@Table(name="CARS")
public class Car {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="CAR_ID")
    private int id;

    @Column(name="CAR_MAKER")
    private String maker;

    @OneToMany(mappedBy="car")
    private Collection<CarModel> models =new ArrayList<CarModel>();

    ......
    Getters and Setters go here
    ......
}

CarModel.java

@Entity
@Table(name="CAR_MODELS")
public class CarModel {


    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="MODEL_ID")
    private int modelId;

    @Column(name="MODEL_NAME")
    private String modelName;

    @ManyToOne
    @JoinColumn(name="CAR_ID")
    private Car car;

    @OneToMany(mappedBy="model")
    private Collection<CarVariant> variants = new ArrayList<CarVariant>();

    ......
    Getters and Setters go here
    ......
}

CarVariant.java

@Entity
@Table(name="CAR_VARIANT")
public class CarVariant {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column (name="VARIANT_ID")
    private int variantId;

    @Column(name="VARIANT_NAME")
    private String variantName;

    @Column(name="FUEL_TYPE")
    private String fuelType;

    @ManyToOne
    @JoinColumn(name="MODEL_ID")
    private CarModel model;

    ..........
      Getters and setters go here
    ..........


}

And finally, User.java

@Entity
@Table(name="MASUSER")
public class User {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="USER_REC_ID")
    private int recordId;

    @Column(name="USER_ID")
    private String id;

    @Column(name="USER_NAME")
    private String name;

    @Column(name="USER_EMAIL_ID")
    private String emailId;

    @Column(name="USER_PHONE")
    private String phone;


    private Collection<Car> cars = new ArrayList<Car>();

}

Now, here's my question.

In real life, a user may own many cars, each one with a specific make, model and variant. I would like to implement such a feature with JPA/Hibernate.

I can define a @ManyToMany relationship to User and Car. In that case, if I do user.getCars().getModels() or user.getCars().getModels().get(0).getVariants() I end up getting everything that's there in the DB.

How do I map User and Car in such a way that I get the following output?

--------------------------------------------------------
| USER_ID     | CAR_ID     | MODEL_ID    | VARIANT_ID  |
--------------------------------------------------------
| 1           | 1          | 2           | 3           |
--------------------------------------------------------
| 1           | 1          | 2           | 2           |
--------------------------------------------------------
| 3           | 2          | 1           | 1           |
--------------------------------------------------------

Also, if you feel I haven't designed my Entity classes right, please feel free to let me know how I can improve.

Thanks

Upvotes: 1

Views: 282

Answers (2)

Michele Mariotti
Michele Mariotti

Reputation: 7469

It's not clear why you need such a table with all keys from nested relations.

My two cents:

@MappedSuperclass
public abstract class AbstractEntity
{
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column
    private Long id;

    ......
    Getters and Setters go here
    ......
}

@Entity
@Table(name = "MANUFACTURER")
public class Manufacturer extends AbstractEntity 
{
    @Column
    private String name;

    @OneToMany(mappedBy = "manufacturer")
    private Set<CarModel> models = new LinkedHashSet<>();

    ......
    Getters and Setters go here
    ......
}

@Entity
@Table(name = "CAR_MODEL")
public class CarModel extends AbstractEntity 
{
    @NotNull
    @ManyToOne(optional = false)
    @JoinColumn(name = "MANUFACTURER_ID")
    private Manufacturer manufacturer;

    @Column
    private String name;

    @OneToMany(mappedBy = "model")
    private Set<CarVariant> variants = new LinkedHashSet<>();

    ......
    Getters and Setters go here
    ......
}

@Entity
@Table(name = "CAR_VARIANT")
public class CarVariant extends AbstractEntity 
{
    @NotNull
    @ManyToOne(optional = false)
    @JoinColumn(name = "CAR_MODEL_ID")
    private CarModel model;

    @Column
    private String name;

    @Column(name="FUEL_TYPE")
    private String fuelType;

    @OneToMany(mappedBy="variant")
    private Set<Car> cars = new LinkedHashSet<>();

    ......
    Getters and Setters go here
    ......
}

@Entity
@Table(name = "CAR")
public class Car extends AbstractEntity 
{
    @NotNull
    @ManyToOne(optional = false)
    @JoinColumn(name = "CAR_VARIANT_ID")
    private CarVariant variant;

    @Column(name = "REGISTRATION_NUMBER")
    private String registrationNumber;


    @ManyToMany(mappedBy = "cars")
    private Set<User> users = new LinkedHashSet<>();

    ......
    Getters and Setters go here
    ......
}

@Entity
@Table(name = "USER")
public class User extends AbstractEntity 
{
    @Column
    private String name;

    @Column
    private String email;

    @Column
    private String phone;

    @ManyToMany
    @JoinTable(name = "USER_CAR", joinColumns = @JoinColumn(name = "USER_ID"), inverseJoinColumns = @JoinColumn(name = "CAR_ID"))
    private Set<Car> cars = new LinkedHashSet<>();

    ......
    Getters and Setters go here
    ......
}
  1. avoid Collections: use Sets where possible (LinkedHashSet), or Lists when you need an @OrderColumn
  2. give simple names: avoid MODEL_NAME, just use NAME
  3. use a @MappedSuperclass, especially if you have a surrogate id for all entities

you can now:

Car car = ...;
String manufacturerName = car.getVariant().getModel().getManufacturer().getName();

String jpql = "select c from Car c where c.variant.model.name = 'Golf' and c.variant.fuelType = 'Diesel'";

Upvotes: 0

user5622465
user5622465

Reputation:

If you fetch the main object like this

Criteria criteria=session.createCriteria(User.class);
List<Object> list=criteria.list();
User user=(User)list.get(0);
Car car=user.getCar();
CarModel carModel=car.getCarModel();
CarVarient carVarient=carModel.getCarVarient();

In this way you can get each object you are trying to fetch but keep in mind that you are using FethType.LazyAnd cascadeType.All in everyPojo

Upvotes: 1

Related Questions