我在我的Web应用程序中使用JPA,但无法弄清如何持久化彼此相关的两个新实体。这是一个例子:
这是两个实体:
消费者(Consumer):具有id和其他一些值。
ProfilePicture:将消费者(Consumer)的id用作自己的主键和外键。(因为没有消费者就不会有ProfilePicture,并且并非每个消费者都有ProfilePicture)
我使用NetBeans生成了实体类和会话bean(facade)。
所以当我想创建一个具有其个人资料图片的消费者时,我认为应该像这样做:
据我所了解的问题,是由于 ProfilePicture 不知道 Consumer 的 id,因此实体无法持久化。
唯一有效的方法是先持久化 Consumer,将其id设置为 ProfilePicture 的id,然后再持久化图片:
然而这两个表只是一个例子,数据库自然更加复杂,手动设置id似乎非常不灵活,我担心会使事情变得过于复杂。特别是因为我不能在一个事务中持久化所有实体(这似乎非常低效)。
我做得对吗?还是有另一种更标准的方法?
编辑:我的解决方案
正如FTR建议的那样,一个问题是ProfilePicture表缺少
现在表格看起来像这样:
+-----------------+ +--------------------+ | Consumer | | ProfilePicture | +-----------------+ +--------------------+ | id (PK) |_ | id (PK) | | userName | \_| consumerId (FK) | +-----------------+ | url | +--------------------+
然后Alan Hay告诉我始终将添加/删除关系封装起来,然后可以确保正确性,我也这样做了。
由于ProfilePicture现在有自己的ID,它变成了OneToMany关系,因此每个消费者现在可以拥有许多个头像。这不是我最初想要的,但我可以接受 :) 因此,我不能仅将头像设置为消费者,而必须将其添加到图片集合中(如上所示)。
这是我实现的唯一附加方法,现在它可以工作了。再次感谢您的所有帮助!
这是两个实体:
消费者(Consumer):具有id和其他一些值。
ProfilePicture:将消费者(Consumer)的id用作自己的主键和外键。(因为没有消费者就不会有ProfilePicture,并且并非每个消费者都有ProfilePicture)
我使用NetBeans生成了实体类和会话bean(facade)。
Consumer.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 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 不知道 Consumer 的 id,因此实体无法持久化。
唯一有效的方法是先持久化 Consumer,将其id设置为 ProfilePicture 的id,然后再持久化图片:
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告诉我始终将添加/删除关系封装起来,然后可以确保正确性,我也这样做了。
Consumer.java
public void addProfilePicture(ProfilePicture profilePicture) {
profilePicture.setConsumerId(this);
if (profilePictureCollection == null) {
this.profilePictureCollection = new ArrayList<>();
}
this.profilePictureCollection.add(profilePicture);
}
由于ProfilePicture现在有自己的ID,它变成了OneToMany关系,因此每个消费者现在可以拥有许多个头像。这不是我最初想要的,但我可以接受 :) 因此,我不能仅将头像设置为消费者,而必须将其添加到图片集合中(如上所示)。
这是我实现的唯一附加方法,现在它可以工作了。再次感谢您的所有帮助!