问题
I am trying to create the follow structure using Hibernate with annotations:
To create a ManyToMany relationship I had created two classes called SessionRiu and SessionRiuId (pk). This way the Session class has two foreign keys (agend_id and user_id) but when I try to create the OneToMany from operation the hibernate does not create the foreign using the id from session:
Session FKs:
Operation FKs (empty):
As I am beginner in java and hibernate, I would appreciate any suggest about my code.
My goal is to create correctly the relationship of these four tables and finally create the fk of Operation class using jpa with the column Operation.session_id reference Session.id.
Exactly that: ALTER TABLE Operation ADD FOREIGN KEY (session_id) REFERENCES Sessions(id)
My files:
Base Class:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.riuapp.model;
import java.util.Calendar;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
/**
*
* @author vdasilva
*/
@MappedSuperclass
public abstract class Base {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
Long id;
@Column(name="status")
private StatusEnum status;
@Column(name = "dt_create", columnDefinition="DATETIME")
@Temporal(TemporalType.TIMESTAMP)
private Date dt_create;
@Column(name = "dt_update", columnDefinition="DATETIME")
@Temporal(TemporalType.TIMESTAMP)
private Date dt_update;
public Base(){
this.dt_create = new Date();
}
///*************************************************************************
///GETTERS AND SETTERS
///*************************************************************************
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Enumerated(EnumType.ORDINAL)
public StatusEnum getStatus() {
return this.status;
}
public void setStatus(StatusEnum status) {
this.status = status;
}
/**
* @return the dt_create
*/
public Date getDt_create() {
return dt_create;
}
/**
* @param dt_create the dt_create to set
*/
public void setDt_create(Date dt_create) {
this.dt_create = dt_create;
}
/**
* @return the dt_update
*/
public Date getDt_update() {
return dt_update;
}
/**
* @param dt_update the dt_update to set
*/
public void setDt_update(Date dt_update) {
this.dt_update = dt_update;
}
}
Agent class:
package com.riuapp.model;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="Agents", catalog = "TestMvn")
public class Agent extends Base implements java.io.Serializable {
/*@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@SuppressWarnings("FieldMayBeFinal")
private List<SessionRiu> sessions;*/
HashSet<SessionRiu> sessions = new HashSet<SessionRiu>(0);
@Column(name="name")
String name;
@Column(name="login")
String login;
@Column(name="pass")
String pass;
@Column(name="description")
String description;
@Column(name="client_id")
Long client_id;
public Agent(Long id, String name, String description) {
//this.sessions = new ArrayList<SessionRiu>();
this.id = id;
this.name = name;
this.description = description;
}
public Agent() {
//this.sessions = new ArrayList<SessionRiu>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Long getClientId() {
return client_id;
}
public void setClientId(Long x) {
this.client_id = x;
}
@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.agent", cascade=CascadeType.ALL)
public Set<SessionRiu> getSessions() {
return this.sessions;
}
public void setSessions(HashSet<SessionRiu> sessions) {
this.sessions = sessions;
}
}
User class:
package com.riuapp.model;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="Users", catalog = "TestMvn")
public class User extends Base implements java.io.Serializable {
private String name;
private String description;
private Long client_id;
private HashSet<SessionRiu> sessions = new HashSet<SessionRiu>(0);
public User(Long id, String name, String description) {
// this.sessions = new ArrayList<SessionRiu>();
this.id = id;
this.name = name;
this.description = description;
}
public User() {
//this.sessions = new ArrayList<SessionRiu>();
}
@Column(name="name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Column(name="description")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Column(name="client_id")
public Long getClientId() {
return client_id;
}
public void setClientId(Long x) {
this.client_id = x;
}
@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.user", cascade=CascadeType.ALL)
public Set<SessionRiu> getSessions() {
return this.sessions;
}
public void setSessions(HashSet<SessionRiu> sessions) {
this.sessions = sessions;
}
}
SessionRiuId class:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.riuapp.model;
import javax.persistence.Embeddable;
import javax.persistence.ManyToOne;
@Embeddable
public class SessionRiuId implements java.io.Serializable {
private Agent agent;
private User user;
@ManyToOne
public Agent getAgent() {
return agent;
}
public void setAgent(Agent agent) {
this.agent = agent;
}
@ManyToOne
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SessionRiuId that = (SessionRiuId) o;
if (agent != null ? !agent.equals(that.agent) : that.agent != null) return false;
if (user != null ? !user.equals(that.user) : that.user != null)
return false;
return true;
}
public int hashCode() {
int result;
result = (agent != null ? agent.hashCode() : 0);
result = 31 * result + (user != null ? user.hashCode() : 0);
return result;
}
}
Session Class:
package com.riuapp.model;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.AssociationOverride;
import javax.persistence.AssociationOverrides;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
@Entity
@Table(name = "Sessions", catalog = "TestMvn")
@AssociationOverrides({
@AssociationOverride(name = "pk.agent",
joinColumns = @JoinColumn(name = "agent_id")),
@AssociationOverride(name = "pk.user",
joinColumns = @JoinColumn(name = "user_id")) })
public class SessionRiu extends Base implements java.io.Serializable{
private SessionRiuId pk = new SessionRiuId();
@OneToMany(fetch = FetchType.LAZY, mappedBy = "sessionriu", cascade=CascadeType.ALL, orphanRemoval = true)
private HashSet<Operation> operations = new HashSet<Operation>(0);
@EmbeddedId
public SessionRiuId getPk() {
return pk;
}
public void setPk(SessionRiuId pk) {
this.pk = pk;
}
@Transient
public Agent getAgent() {
return getPk().getAgent();
}
public void setAgent(Agent agent) {
this.getPk().setAgent(agent);
}
@Transient
public User getUser() {
return this.getPk().getUser();
}
public void setUser(User user) {
this.getPk().setUser(user);
}
private StateEnum state;
@Column(name="duration")
private double duration;
@Column(name="ip")
private String ip;
@Column(name="browser")
private String browser;
public SessionRiu(Agent a, User u) {
this.state = StateEnum.STATE0;
this.getPk().setAgent(a);
this.getPk().setUser(u);
}
public SessionRiu(StateEnum x, Agent a, User u) {
this.state = x;
this.getPk().setAgent(a);
this.getPk().setUser(u);
}
/**
* @return the state
*/
public StateEnum getState() {
return state;
}
/**
* @param state the state to set
*/
public void setState(StateEnum state) {
this.state = state;
}
/**
* @return the duration
*/
public double getDuration() {
return duration;
}
/**
* @param duration the duration to set
*/
public void setDuration(double duration) {
this.duration = duration;
}
/**
* @return the ip
*/
public String getIp() {
return ip;
}
/**
* @param ip the ip to set
*/
public void setIp(String ip) {
this.ip = ip;
}
/**
* @return the browser
*/
public String getBrowser() {
return browser;
}
/**
* @param browser the browser to set
*/
public void setBrowser(String browser) {
this.browser = browser;
}
public HashSet<Operation> getOperations() {
return this.operations;
}
public void setOperations(HashSet<Operation> operations) {
this.operations = operations;
}
}
And finally the Operation class:
package com.riuapp.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "Operation", catalog = "TestMvn")
public class Operation extends Base implements java.io.Serializable{
@ManyToOne
@JoinColumn(referencedColumnName = "id")
private SessionRiu sessionRiu;
private StateEnum state;
private ResultEnum result;
@Column(name="duration")
private double duration;
@Column(name="ip")
private String ip;
@Column(name="browser")
private String browser;
public Operation(SessionRiu sessionRiu) {
this.state = StateEnum.STATE0;
this.result = ResultEnum.PENDING;
this.sessionRiu = sessionRiu;
}
public Operation(SessionRiu sessionRiu, StateEnum state, ResultEnum result) {
this.state = state;
this.result = result;
this.sessionRiu = sessionRiu;
}
/**
* @return the state
*/
public StateEnum getState() {
return state;
}
/**
* @param state the state to set
*/
public void setState(StateEnum state) {
this.state = state;
}
/**
* @return the duration
*/
public double getDuration() {
return duration;
}
/**
* @param duration the duration to set
*/
public void setDuration(double duration) {
this.duration = duration;
}
/**
* @return the ip
*/
public String getIp() {
return ip;
}
/**
* @param ip the ip to set
*/
public void setIp(String ip) {
this.ip = ip;
}
/**
* @return the browser
*/
public String getBrowser() {
return browser;
}
/**
* @param browser the browser to set
*/
public void setBrowser(String browser) {
this.browser = browser;
}
public SessionRiu getSessionRiu()
{
return this.sessionRiu;
}
public void setSessionRiu(SessionRiu sessionRiu)
{
this.sessionRiu = sessionRiu;
}
}
Observation:
if I remove the join line are created two fks (agent_id and user_id) as the session table =(
@Entity
@Table(name = "Operation", catalog = "TestMvn")
public class Operation extends Base implements java.io.Serializable{
@ManyToOne
//@JoinColumn(referencedColumnName = "id")
private SessionRiu sessionRiu;
回答1:
Bottom line, you already have an id
in Session
table so there is no need for a composite-id. The mapping looks like this:
@Entity
@Table(name = "Sessions", catalog = "TestMvn")
public class SessionRiu extends Base implements java.io.Serializable {
@Id
private Long id;
@ManyToOne
private User user;
@ManyToOne
private Agent agent;
//other mappings here
}
This way, you don't even need the @EmbeddableId
class.
Now, you need a mappedBy
@OneToMany
in Agent
and User
:
@Entity
@Table(name="Users", catalog = "TestMvn")
public class User extends Base implements java.io.Serializable {
@Id
private Long id;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy="user")
private List<SessionRiu> sessions = new ArrayList<>();
//other mappings here
}
@Entity
@Table(name="Agents", catalog = "TestMvn")
public class Agent extends Base implements java.io.Serializable {
@Id
private Long id;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy="agent")
private List<SessionRiu> sessions = new ArrayList<>();
//other mappings here
}
And the same in Operation
:
@Entity
@Table(name = "Operation", catalog = "TestMvn")
public class Operation extends Base implements java.io.Serializable{
@Id
private Long id;
@ManyToOne
private SessionRiu sessionRiu;
//other mappings here
}
回答2:
JPA does not allow relationships within an embedded ID, and since your Session table has an ID field, I'm not quite sure what you were after by trying to put the Agent and User references in an embedded id. The simplest model that would match your table structure would be of the form:
@Table(name="Agents", catalog = "TestMvn")
public class Agent {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
Long id;
@OneToMany(mappedby='agent', cascade = CascadeType.ALL, orphanRemoval = true)
private List<SessionRiu> sessions;
}
@Entity
@Table(name = "Sessions", catalog = "TestMvn")
public class SessionRiu implements java.io.Serializable{
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
Long id;
@ManyToOne
@JoinColumn(name = "agent_id")
private Agent agent;
}
Adding in User and Operation would follow the same pattern.
If you want a composite PK in session instead of using session's id field, JPA 2.1 allows something like:
@Entity
@Table(name = "Sessions", catalog = "TestMvn")
@IdClass(SessionRiuPK.class)
public class SessionRiu implements java.io.Serializable{
@Id
@ManyToOne
@JoinColumn(name = "agent_id")
private Agent agent;
@Id
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
...
}
With
public class SessionRiuPK {
Long user;
Long agent;
}
来源:https://stackoverflow.com/questions/38204233/manytoone-annotation-to-specific-column