JPA simple many-to-many with eclipselink

风格不统一 提交于 2019-12-04 03:58:31

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!