使用eclipselink的JPA简单多对多 [英] JPA simple many-to-many with eclipselink

查看:92
本文介绍了使用eclipselink的JPA简单多对多的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个ER图:

那被翻译成这些类:

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;

现在,我将添加一个实体User和Notify并在它们之间创建一个关系. 因此,我编写了以下代码段:

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);

但是我收到此错误:

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???????????

推荐答案

该错误的原因可能在于远程通信.您正在使用外观的事实意味着您正在与后端进行远程通信.

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.

这意味着您在uhn实例上设置的usernotify实例将被发送以保留在远程系统上,而本地实例则永远不会收到生成的ID.

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:

保存usernotify后,从后端获取它们.这应该返回具有现有ID的持久化实例.然后,您可以使用它们来存储您的uhn关系.

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.

编辑:我错过了UserHasNotify是具有嵌入式ID的有状态关系这一事实.在代码中,您永远不会设置此ID,因此提供程序会错过它.

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.

在这种情况下,我建议使用IdClass而不是嵌入的ID-映射更易读,因此您可能不会两次映射UserNotify关系-一次嵌入PK,然后再次进入实体;)

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 ;)

这是它的样子:

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.

这篇关于使用eclipselink的JPA简单多对多的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆