问题
I've this ER diagram:

That was translated into these classes:
User.java
@Entity
@Table(name = "user")
@NamedQueries({
@NamedQuery(name = "User.findAll", query = "SELECT u FROM User u")})
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@Column(name = "name")
private String name;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
private Collection<UserHasNotify> userHasNotifyCollection;
UserHasNotify.java
@Entity
@Table(name = "user_has_notify")
@NamedQueries({
@NamedQuery(name = "UserHasNotify.findAll", query = "SELECT u FROM UserHasNotify u")})
public class UserHasNotify implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
protected UserHasNotifyPK userHasNotifyPK;
@Column(name = "has_read")
private String hasRead;
@JoinColumn(name = "notify_id", referencedColumnName = "id", insertable = false, updatable = false)
@ManyToOne(optional = false)
private Notify notify;
@JoinColumn(name = "user_id", referencedColumnName = "id", insertable = false, updatable = false)
@ManyToOne(optional = false)
private User user;
UserHasNotifyPK.java
@Embeddable
public class UserHasNotifyPK implements Serializable {
@Basic(optional = false)
@Column(name = "user_id")
private int userId;
@Basic(optional = false)
@Column(name = "notify_id")
private int notifyId;
Notify.java
@Entity
@Table(name = "notify")
@NamedQueries({
@NamedQuery(name = "Notify.findAll", query = "SELECT n FROM Notify n")})
public class Notify implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@Column(name = "message")
private String message;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "notify")
private Collection<UserHasNotify> userHasNotifyCollection;
Now, I would to add an entity User and Notify and create a relation between them. So I've wrote this snippet:
User user = new User();
user.setName("John");
Notify notify = new Notify();
notify.setMessage("Hello World");
userFacade.create(user);
notifyFacade.create(notify);
UserHasNotify uhn = new UserHasNotify();
uhn.setNotify(notify);
uhn.setUser(user);
uhn.setHasRead("ok");
uhnFacade.create(uhn);
But I receive this error:
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'user_id' cannot be null
Error Code: 1048
Call: INSERT INTO user_has_notify (has_read, user_id, notify_id) VALUES (?, ?, ?)
bind => [3 parameters bound]
Query: InsertObjectQuery(com.test.entity.UserHasNotify[ userHasNotifyPK=null ])
Why???????????
回答1:
The reason for the error may lie in remote communicaton. The fact that you are using the facades implies that you are communicating with your backend remotely.
This would mean that the user
and notify
instances you are setting on the uhn
instance are sent to be persisted on the remote system, while the local instances never receive the generated ids.
To verify and fix this, you can extend your example:
After saving the user
and notify
, fetch them from your backend. This should return persisted instances with existing Ids. Then you can use them to store your uhn
relation.
EDIT: I have missed the fact that the UserHasNotify
is a stateful relationship with an embededd Id. In the code you never set this Id, so the provider misses it.
For this case, I would advise to use an IdClass
instead of an embededd Id - the mapping is more readable, so you would probably not have mapped the User
and Notify
relation twice - once in the embedded PK and once again in the entity ;)
Here is what it would look like:
public class UserHasNotifyPK implements Serializable {
private Notify notify;
private User user;
...
}
.
@Entity
@Table(name = "user_has_notify")
@IdClass(UserHasNotifyPK.class)
@NamedQueries({
@NamedQuery(name = "UserHasNotify.findAll", query = "SELECT u FROM UserHasNotify u")})
public class UserHasNotify implements Serializable {
private static final long serialVersionUID = 1L;
@Column(name = "has_read")
private String hasRead;
@Id
@JoinColumn(name = "notify_id", referencedColumnName = "id", insertable = false, updatable = false)
@ManyToOne(optional = false)
private Notify notify;
@Id
@JoinColumn(name = "user_id", referencedColumnName = "id", insertable = false, updatable = false)
@ManyToOne(optional = false)
private User user;
You can then try the same test again.
来源:https://stackoverflow.com/questions/14752695/jpa-simple-many-to-many-with-eclipselink