简体   繁体   中英

Spring JPA - Data integrity relationships

I'm new to Java and even more newer to Spring (Boot and JPA) but I was curious, I'm trying to debug an issue that says, "No identifier specified for entity".

For illustartion purposes, I've created the following tables from this diagram:

在此处输入图片说明

Originally, there was a M:N relationship between the user and vehicle table, so I created an associative entity (UserVehicleAsso) to split the two up. I was following this guide on M:N mapping in Java, http://viralpatel.net/blogs/hibernate-many-to-many-annotation-mapping-tutorial/

For the most part, it was pretty straight forward but my question is, within the associative entity (UserVehicleAsso), do I have to use the @Id annotation for each of the foreign keys? I assume that I didn't need to because those were automatically generated from each of the respective tables.

Let me know your thoughts or comments, thanks.

Also, below is the code that I used to generate these models:

For the User table/class:

@Entity
public class User {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int userId;

private String fName;
private String lName;

@ManyToMany(cascade = {CascadeType.ALL})
@JoinTable(name="userVehicleAsso", 
            joinColumns={@JoinColumn(name="userID")}, 
            inverseJoinColumns={@JoinColumn(name="vehicleID")})
private Set<Vehicle> vehicles = new HashSet<Vehicle>();


//constructor
protected User() {}


public int getUserId() {
    return userId;
}
public void setUserId(int userId) {
    this.userId = userId;
}
public String getFName() {
    return fName;
}
public void setFName(String fName) {
    this.fName = fName;
}
public String getLName() {
    return lName;
}
public void setLName(String lName) {
    this.lName = lName;
}



public Set<Vehicle> getVehicles() {
    return vehicles;
}

public void setVehicles(Set<Vehicle> vehicles) {
    this.vehicles = vehicles;
}

@Override 
public String toString() {
    return getFName() + "," + getLName();
}}

For the Vehicle table/class:

@Entity
public class Vehicle {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int vehicleId;

private String brand;
private String model;
//foreign key mappings
//mapping with associative
@ManyToMany(mappedBy="vehicles")
private Set<User> users = new HashSet<User>();


//constructors
protected Vehicle() {}

public Vehicle(int id) {
    this.vehicleId = id;
}

public Vehicle (String brand, String model) {
    this.brand = brand;
    this.model = model;
}

/*  public Vehicle() {

}*/


public int getVehicleId() {
    return vehicleId;
}
public Set<User> getUsers() {
    return users;
}

public void setUsers(Set<User> users) {
    this.users = users;
}


public void setVehicleId(int vehicleId) {
    this.vehicleId = vehicleId;
}
public String getBrand() {
    return brand;
}

public void setBrand(String brand) {
    this.brand = brand;
}

public String getModel() {
    return model;
}

public void setModel(String model) {
    this.model = model;
}
@Override
public String toString() {
    // + setBodyType() + "," +
    return getBrand() + "," + getModel();
}


}

And then finally, my associtive table/class:

@Entity
public class UserVehicleAsso{

private int userID;
private int vehicleID;

public int getUserID() {
    return userID;
}
public void setUserID(int userID) {
    this.userID = userID;
}
public int getVehicleID() {
    return vehicleID;
}
public void setVehicleID(int vehicleID) {
    this.vehicleID = vehicleID;
}


}

In my opinion, it's not necessary to have an Entity class for the middle table in your case. The table will be generated automatically if configured correctly. In this table, there would not be column ID , only two columns with userID and vehicleID data.

Now, if your middle table has more than what are needed to establish the M:N relationship, then your middle Entity class is needed, and the ID of it, too. For example, if this class is intended to store the time stamp every time a relationship is established, you have to:

  1. Create this Entity class,
  2. Give it an ID field with proper generation strategy,
  3. Map the time stamp with a field with adequate type, annotation/XML mapping and so on.

This part of JPA/Hibernate have confused me a lot and I used to get into them. If my memory serves me well this is the proper/perfect way how things should work.

You can specify a composite primary key class that is mapped to multiple fields or properties of the entity.

Here are sample codes:

public class ActivityRegPK implements Serializable {
    private int activityId;

    private int memberId;

    public int getActivityId() {
        return activityId;
    }

    public void setActivityId(int activityId) {
        this.activityId = activityId;
    }

    public int getMemberId() {
        return memberId;
    }

    public void setMemberId(int memberId) {
        this.memberId = memberId;
    }
}

associtive table/class:

@IdClass(ActivityRegPK.class)
@Entity
@Table(name="activity_reg")
@NamedQuery(name="ActivityReg.findAll", query="SELECT a FROM ActivityReg a")
public class ActivityReg implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name="activity_id")
    private int activityId;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="ins_date")
    private Date insDate;

    @Id
    @Column(name="member_id")
    private int memberId;
}

Activity.class

@Entity
@NamedQuery(name="Activity.findAll", query="SELECT a FROM Activity a")
public class Activity implements Serializable {
    // some attributes
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM