gpt4 book ai didi

java - JPA 处理关系的 merge()

转载 作者:行者123 更新时间:2023-11-30 08:09:17 25 4
gpt4 key购买 nike

我有一个单向关系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 创建方法时的上下文(它由 JSF @ManagedBean 调用):

  • project.projectTypeDETACHED
  • 项目
  • 没有处于 Activity 状态的事务(我正在使用 JTA/CMT)

我不是在问 persist()merge() 之间的区别,我是在问是否其中之一

  1. 如果em.persist(project)自动“重新附加”project.projectType(我想不会)
  2. 如果调用顺序合法:首先em.persist(project),然后em.merge(projectType)或者如果应该被颠倒
  3. 因为 em.merge(projectType) 返回一个不同的实例,如果需要调用 project.setType(managementProjectType)

也欢迎解释“为什么”它以某种方式起作用,而以另一种方式不起作用。

最佳答案

您只需要 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.

如果您在 entity 已被管理的情况下调用 manage(entity),则不会发生任何事情。

调用persist(entity)也会使您的实体受到管理,但它不会返回任何副本。相反,它会合并原始对象,并且还可能调用 ID 生成器(例如序列),但使用 merge 时情况并非如此。

参见this answer了解有关 persistmerge 之间差异的更多详细信息。

这是我的建议:

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".
}

更新

if em.persist(project) automatically "reattach" project.projectType (I suppose not)

没有。您可能会收到一个异常(Hibernate 无论如何都会这样做),指出您正在尝试与 transient 引用合并。

更正:我用 Hibernate 对其进行了测试,没有发现任何异常。该项目是使用非托管项目类型创建的(该类型是托管的,然后在持久化项目之前分离)。 但是项目类型的进度没有如预期那样增加,因为它不受管理。所以,是的,在坚持项目之前对其进行管理。

if it is legal the call order: first em.persist(project) then em.merge(projectType) or if it should be inverted

这样做是最佳做法。但是,当这两个语句在同一批处理中执行时(在实体管理器刷新之前),它甚至可能起作用(在持久化项目之后合并类型)。在我的测试中它无论如何都有效。但正如我所说,最好在保留新实体之前合并实体。

since em.merge(projectType) returns a different instance, if it is required to call project.setType(managedProjectType)

是的。请参阅上面的示例。持久性提供程序可能返回相同的引用,但这不是必需的。因此,为了确保安全,请调用 project.setType(mergedType)

关于java - JPA 处理关系的 merge(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30649467/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com