繁体   English   中英

如何使用JPA保留两个实体

[英]How to persist two entities with JPA

我在我的Web应用程序中使用了JPA,但我不知道如何持久化彼此相关的两个新实体。 这里是一个例子:

这是两个实体

+-----------------+   +--------------------+
|     Consumer    |   |   ProfilePicture   |
+-----------------+   +--------------------+
| id    (PK)      |---| consumerId (PPK+FK)|
| userName        |   | url                |
+-----------------+   +--------------------+

消费者有一个ID和其他一些值。 ProfilePicture使用使用者ID作为其自己的主键和外键。 (由于没有使用者,ProfilePicture将不存在,并且并非每个使用者都具有ProfilePicture)

我使用NetBeans生成实体类和会话bean(外观)。

简而言之就是这样

消费者.java

@Entity
@Table(name = "Consumer")
@NamedQueries({...})
public class Consumer implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;

    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 50)
    @Column(name = "userName")
    private String userName;     

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "consumer")
    private ProfilePicture profilePicture;

    /* and all the basic getters and setters */
    (...)
}

ProfilePicture.java

@Entity
@Table(name = "ProfilePicture")
@XmlRootElement
@NamedQueries({...})
public class ProfilePicture implements Serializable {

    @Id
    @Basic(optional = false)
    @NotNull
    @Column(name = "consumerId")
    private Integer consumerId;

    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 255)
    @Column(name = "url")
    private String url;

    @JoinColumn(name = "consumerId", referencedColumnName = "id", insertable = false, updatable = false)
    @OneToOne(optional = false)
    private Consumer consumer;

    /* and all the basic getters and setters */
    (...)
}

因此,当我想用​​他的ProfilePicture创建一个Consumer时 ,我想我会这样做:

   ProfilePicture profilePicture = new ProfilePicture("http://www.url.to/picture.jpg");  // create the picture object
   Consumer consumer = new Consumer("John Doe"); // create the consumer object

   profilePicture.setConsumer(consumer);        // set the consumer in the picture (so JPA can take care about the relation      
   consumerFacade.create(consumer);             // the facade classes to persist the consumer
   profilePictureFacade.create(profilePicture);  // and when the consumer is persisted (and has an id) persist the picture

我的问题

我几乎尝试了每种组合的所有方法,但JPA似乎无法自行链接两个实体。 大多数时候,我会收到如下错误:

 EJB5184:A system exception occurred during an invocation on EJB ConsumerFacade, method: public void com.me.db.resources.bean.ConsumerFacade.create(com.mintano.backendclientserver.db.resources.entity.Consumer)
 (...) 
Bean Validation constraint(s) violated while executing Automatic Bean Validation on callback event:'prePersist'. Please refer to embedded ConstraintViolations for details.

据我了解的问题,这是因为ProfilePicture不知道使用者的ID,因此实体无法持久。

它唯一有效的方法是,首先持久保存Consumer ,将其id设置为ProfilePicture ,然后持久保存图片:

   ProfilePicture profilePicture = new ProfilePicture("http://www.url.to/picture.jpg");  // create the picture object
   Consumer consumer = new Consumer("John Doe"); // create the consumer object

   consumerFacade.create(consumer);             // the facade classes to persist the consumer
   profilePicture.setConsumerId(consumer.getId()); // set the consumer's new id in the picture     

   profilePictureFacade.create(profilePicture);  // and when the consumer is persisted (and has an id) persist the picture

但是,这两个表只是一个示例,自然数据库要复杂得多,像这样手动设置id似乎很不灵活,而且我担心事情会变得过于复杂。 特别是因为我无法将所有实体都保留在一个事务中(这似乎效率很低)。

我做对了吗? 还是有另一种更标准的方法?

编辑:我的解决方案

正如FTR所建议的那样,一个问题是ProfilePicture表的id缺失(我将Consumer.id用作外部和主要)。

这些表现在看起来像这样:

+-----------------+   +--------------------+
|     Consumer    |   |   ProfilePicture   |
+-----------------+   +--------------------+
| id    (PK)      |_  | id (PK)            |
| userName        | \_| consumerId (FK)    |
+-----------------+   | url                |
                      +--------------------+

然后, 艾伦·海伊Alan Hay)告诉我, 始终封装对关系的添加/删除,然后可以确保正确性 ,我这样做了:

消费者.java

public void addProfilePicture(ProfilePicture profilePicture) {
    profilePicture.setConsumerId(this);  
    if (profilePictureCollection == null) {
        this.profilePictureCollection = new ArrayList<>();
    }
    this.profilePictureCollection.add(profilePicture);
}

由于ProfilePicture现在具有其自己的ID,因此它已成为OneToMany关系,因此每个Consumer现在可以拥有许多个人资料图片。 那不是我最初想要的,但是我可以忍受它:)因此,我不能只为使用者设置一个ProfilePicture,而必须将其添加到Pictures的集合中(如上所述)。

这是我实施的唯一附加方法,现在可以使用。 再次感谢你的帮助!

当持久保留关系的非所有权方的实例(包含“ mappedBy”并且在您的情况下为“消费者”)时,必须始终确保将关系的双方都设置为具有预期的级联工作。

您当然应该总是这样做,以确保您的域模型正确。

Consumer c = new Consumer();
ProfilePicure p = new ProfilePicture();
c.setProfilePicture(p);//see implementation
//persist c

消费者.java

    @Entity
    @Table(name = "Consumer")
    @NamedQueries({...})
    public class Consumer implements Serializable {

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Basic(optional = false)
        @Column(name = "id")
        private Integer id;

        @Basic(optional = false)
        @NotNull
        @Size(min = 1, max = 50)
        @Column(name = "userName")
        private String userName;     

        @OneToOne(cascade = CascadeType.ALL, mappedBy = "consumer")
        private ProfilePicture profilePicture;

        public void setProfilePicture(ProfilePicture profilePicture){
            //SET BOTH SIDES OF THE RELATIONSHIP
            this.profilePicture = profilePicture;
            profilePicture.setConsumer(this);
        }
}

始终封装添加/删除关系,然后可以确保正确性:

public class Parent{
private Set<Child> children;

public Set<Child> getChildren(){
    return Collections.unmodifiableSet(children); //no direct access:force clients to use add/remove methods
}

public void addChild(Child child){
    child.setParent(this); 
    children.add(child);
}

public class Child(){
    private Parent parent;
}

您可以一次保留一个对象及其子对象。 所以我认为这应该工作:

ProfilePicture profilePicture = new ProfilePicture("http://www.url.to/picture.jpg");  // create the picture object
Consumer consumer = new Consumer("John Doe"); // create the consumer object
consumer.setProfilePicture(profilePicture); 
consumerFacade.create(consumer);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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