我有一个单向关系Project -> ProjectType
:
@Entity
public class Project extends NamedEntity
{
@ManyToOne(optional = false)
@JoinColumn(name = "TYPE_ID")
private ProjectType type;
}
@Entity
public class ProjectType extends Lookup
{
@Min(0)
private int progressive = 1;
}
请注意,没有级联。
现在,当我插入一个新项目时,我需要递增渐进式。
这就是我在EJB中所做的事情,但我不确定它是最好的方法:
public void create(Project project)
{
em.persist(project);
/* is necessary to merge the type? */
ProjectType type = em.merge(project.getType());
/* is necessary to set the type again? */
project.setType(type);
int progressive = type.getProgressive();
type.setProgressive(progressive + 1);
project.setCode(type.getPrefix() + progressive);
}
我正在使用eclipselink 2.6.0,但我想知道是否存在与实现无关的最佳实践和/或是否存在持久性提供程序之间存在行为差异的情况。
更新
在进入EJB create方法时澄清上下文(由JSF @ManagedBean
调用):
project.projectType
已关闭 project
新 我不是在询问persist()
和merge()
之间的区别,我不知道是否
em.persist(project)
自动"重新附加" project.projectType
(我想不是)em.persist(project)
然后em.merge(projectType)
或是否应该倒置em.merge(projectType)
会返回不同的实例,如果需要调用project.setType(managedProjectType)
解释"为什么"这在某种程度上起作用而在另一种方式中也是受欢迎的。
答案 0 :(得分:2)
您只需要merge(...)
创建由您的实体经理管理的临时实体。根据JPA的实现(不确定EclipseLink),merge
调用的返回实例可能是原始对象的不同副本。
MyEntity unmanaged = new MyEntity();
MyEntity managed = entityManager.merge(unmanaged);
assert(entityManager.contains(managed)); // true if everything worked out
assert(managed != unmanaged); // probably true, depending on JPA impl.
如果您致电manage(entity)
已经管理entity
,则不会发生任何事情。
调用persist(entity)
也会使您的实体受到管理,但不会返回任何副本。相反,它合并原始对象,它也可能调用ID生成器(例如序列),而使用merge
时则不然。
有关persist
和merge
之间差异的详细信息,请参阅this answer。
这是我的建议:
public void create(Project project) {
ProjectType type = project.getType(); // maybe check if null
if (!entityManager.contains(type)) { // type is transient
type = entityManager.merge(type); // or load the type
project.setType(type); // update the reference
}
int progressive = type.getProgressive();
type.setProgressive(progressive + 1); // mark as dirty, update on flush
// set "code" before persisting "project" ...
project.setCode(type.getPrefix() + progressive);
entityManager.persist(project);
// ... now no additional UPDATE is required after the
// INSERT on "project".
}
如果em.persist(项目)自动“重新附加”project.projectType(我想不是)
没有。你可能会得到一个例外(Hibernate无论如何)说明你正在尝试与瞬态引用合并。
更正:我用Hibernate测试了它并没有例外。该项目是使用非托管项目类型创建的(在持久化项目之前已对其进行了管理和分离)。 但项目类型的progression
未按预期递增,因为它未受管理。所以是的,在坚持项目之前管理它。
如果调用顺序是合法的:首先是em.persist(项目)然后是em.merge(projectType)或者是否应该反转
最佳做法是这样做。但是当两个语句在同一批次中执行时(在实体管理器被刷新之前),它甚至可以工作(在持久化项目之后合并类型)。在我的测试中它无论如何都有用。但正如我所说,在坚持新实体之前合并实体会更好。
因为em.merge(projectType)返回一个不同的实例,如果需要调用project.setType(managedProjectType)
是。见上面的例子。持久性提供程序可能返回相同的引用,但不是必需的。所以,请务必致电project.setType(mergedType)
。
答案 1 :(得分:0)
你需要合并吗?这得看情况。根据merge()javadoc:
将给定实体的状态合并到当前持久性中 上下文
您是如何获得附加到项目的ProjectType实例的?如果该实例已经被管理,那么你需要做的只是
type.setProgessive(type.getProgressive() + 1)
并且JPA会自动在下次上下文刷新时发布更新。
否则,如果未管理类型,则需要先将其合并。
虽然没有直接关系,但这个quesetion对于持久化与合并有一些很好的见解:JPA EntityManager: Why use persist() over merge()?
使用em.persist(project)
vs em.merge(projectType)
的调用顺序,您可能应该问自己,如果数据库中的类型消失了会发生什么?如果你首先合并类型,它将被重新插入,如果你先保留项目并且你有FK约束,插入将失败(因为它没有级联)。
答案 2 :(得分:-1)
此代码中的代码。合并基本上将记录存储在不同的对象中,让我们说 一个帐户pojo就在那里 帐户帐户= null; account = entityManager.merge(account); 然后你可以存储这个结果。
但是在你的代码中你使用的是合并不同的条件 public void create(项目项目) { em.persist(项目);
/* is necessary to merge the type? */
ProjectType type = em.merge(project.getType());
} 这里 Project和ProjectType两个不同的pojo你可以使用merge为同一个pojo。 或者你的pojo之间是否有任何关系,你也可以使用它。