JPA处理关系的merge()

时间:2015-06-04 16:37:30

标签: java jpa merge relationship

我有一个单向关系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
  • 没有交易(我使用JTA / CMT)是活跃的

我不是在询问persist()merge()之间的区别,我不知道是否

  1. 如果em.persist(project)自动"重新附加" project.projectType(我想不是)
  2. 如果合法致电订单:先em.persist(project)然后em.merge(projectType)或是否应该倒置
  3. 因为em.merge(projectType)会返回不同的实例,如果需要调用project.setType(managedProjectType)
  4. 解释"为什么"这在某种程度上起作用而在另一种方式中也是受欢迎的。

3 个答案:

答案 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时则不然。

有关persistmerge之间差异的详细信息,请参阅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之间是否有任何关系,你也可以使用它。