我有一个JPA实体已经存在于数据库中 我希望有一个副本(具有不同的ID),并修改了一些字段。
最简单的方法是什么?像:
@Id
字段设置为null
并坚持下去会有效吗?@Id
以外的所有字段)?答案 0 :(得分:48)
使用EntityManager.detach
。它使bean不再链接到EntityManager。然后将Id设置为新Id(如果是自动则设置为null),更改所需的字段并保留。
答案 1 :(得分:14)
使用EclipseLink时,您可以使用非常方便的CopyGroup-Feature:
http://wiki.eclipse.org/EclipseLink/Examples/JPA/AttributeGroup#CopyGroup
一个很大的优点是,如果没有太多的摆弄,它也会正确克隆私人关系。
这是我的代码,使用私人拥有的@ OneToMany关系克隆播放列表只需几行:
public Playlist cloneEntity( EntityManager em ) {
CopyGroup group = new CopyGroup();
group.setShouldResetPrimaryKey( true );
Playlist copy = (Playlist)em.unwrap( JpaEntityManager.class ).copy( this, group );
return copy;
}
确保使用persist()保存此新对象,merge()不起作用。
答案 2 :(得分:4)
我今天面临同样的问题:我在数据库中有一个实体,我想:
我成功完成了以下步骤:
@PersistenceContext(unitName = "...")
private EntityManager entityManager;
public void findUpdateCloneAndModify(int myEntityId) {
// retrieve entity from database
MyEntity myEntity = entityManager.find(MyEntity.class, myEntityId);
// modify the entity
myEntity.setAnAttribute(newValue);
// update modification in database
myEntity = entityManager.merge(myEntity);
// detach entity to use it as a new entity (clone)
entityManager.detach(myEntity);
myEntity.setId(0);
// modify detached entity
myEntity.setAnotherAttribute(otherValue);
// persist modified clone in database
myEntity = entityManager.merge(myEntity);
}
备注:如果我使用' persist'则最后一步(克隆持久性)不起作用而不是“合并”,即使我在调试模式中注意到克隆ID在“坚持”后仍然发生了变化。命令!
我仍然面临的问题是我的第一个实体在分离之前没有被修改过。
答案 3 :(得分:3)
您可以使用像Orika这样的映射框架。 http://orika-mapper.github.io/orika-docs/ Orika是一个Java bean映射框架,可以递归地将数据从一个对象复制到另一个对象。它易于配置,并提供各种灵活性。
以下是我在项目中使用它的方法:
增加了一个依赖性:
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.4.6</version>
</dependency>
然后在代码中使用它如下:
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
MapperFacade mapper=mapperFactory.getMapperFacade();
User mappedUser = mapper.map(oldUser, User.class);
如果你有许多需要这种克隆的用例,这可能会有所帮助。
答案 4 :(得分:2)
正如对已接受答案的评论中所述,detatch将忽略对托管实体的未刷新更改。
如果您使用的是弹簧,则可以使用另一个选项org.springframework.beans.BeanUtils
这里有BeanUtils.copyProperties(Object source, Object target)
。这将允许您在不篡改entityManager的情况下执行浅拷贝。
修改强> 来自api doc的引用:&#34;这种方法旨在执行一个&#34;浅拷贝&#34;不会复制属性和复杂属性(例如,嵌套的属性)。&#34;
This博客文章可能会告诉您有关深度复制Java对象的更多信息。
答案 5 :(得分:0)
正如我在this article中所述,最好使用复制构造函数并精确控制需要克隆哪些属性。
因此,如果您有一个Post
实体,例如:
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
@GeneratedValue
private Long id;
private String title;
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
@OneToOne(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY
)
private PostDetails details;
@ManyToMany
@JoinTable(
name = "post_tag",
joinColumns = @JoinColumn(
name = "post_id"
),
inverseJoinColumns = @JoinColumn(
name = "tag_id"
)
)
private Set<Tag> tags = new HashSet<>();
//Getters and setters omitted for brevity
public void addComment(
PostComment comment) {
comments.add(comment);
comment.setPost(this);
}
public void addDetails(
PostDetails details) {
this.details = details;
details.setPost(this);
}
public void removeDetails() {
this.details.setPost(null);
this.details = null;
}
}
在复制comments
并将其用作新模板的模板时,克隆Post
毫无意义:
Post post = entityManager.createQuery(
"select p " +
"from Post p " +
"join fetch p.details " +
"join fetch p.tags " +
"where p.title = :title", Post.class)
.setParameter(
"title",
"High-Performance Java Persistence, 1st edition"
)
.getSingleResult();
Post postClone = new Post(post);
postClone.setTitle(
postClone.getTitle().replace("1st", "2nd")
);
entityManager.persist(postClone);
您需要添加到Post
实体中的是复制构造函数:
/**
* Needed by Hibernate when hydrating the entity
* from the JDBC ResultSet
*/
private Post() {}
public Post(Post post) {
this.title = post.title;
addDetails(
new PostDetails(post.details)
);
tags.addAll(post.getTags());
}
这是解决实体克隆/复制问题的最佳方法。任何其他尝试使此过程完全自动化的方法,都错失了并非所有属性都值得复制的观点。
答案 6 :(得分:0)
我只是尝试将id设置为null,并且有效
address.setId(null);
address = addrRepo.save(address);
将id设置为null可以使它保存到具有新id的新记录中,因为我会自动生成它。
答案 7 :(得分:0)
ModelMapper库可用于此目的。
public MyEntity clone(MyEntity myInstance) {
MyEntity newInstance = new MyEntity();
new ModelMapper().map(myInstance, newInstance);
return newInstance;
}
只需添加Maven依赖项
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.3.2</version>
</dependency>