2013-04-05 193 views
9

我是新来的整个JPA的东西,所以我有关于处理JPA合并并坚持最佳方式的多个问题。处理JPA合并的最佳方法?

  1. 我有一个用户对象,应该更新(一些值,如日期和名称)。我必须首先合并传递的对象还是安全地找到新对象?

    目前我的更新用户代码如下所示:

    public void updateUserName(User user, String name) { 
        // maybe first merge it? 
        user.setName(name); 
        user.setChangeDate(new Date()); 
        em.merge(user); 
    } 
    

    我如何可以肯定的是被称为更新方法之前用户还没有被操纵?是否更安全地做这样的事情:

    public void updateUserName(int userId, String name) { 
        User user = em.getReference(User.class, userId); 
        user.setName(name); 
        user.setChangeDate(new Date()); 
        em.merge(user); 
    } 
    

    也许其他解决方案?我观看了多个视频,看到了很多例子,但它们都不一样,没有人会解释最佳做法。

  2. 将孩子添加到关系中的最佳方法是什么?例如我的用户对象有一个连接到多个组。我应该为用户调用JPA处理程序,并将新组添加到用户组列表中,还是应该在具有持久性的组处理程序中创建组并将其手动添加到我的用户对象?这里

希望有人有线索;)

+0

见http://stackoverflow.com/questions/1069992/jpa-entitymanager-why-use-persist-over-merge – GKislin 2016-10-03 16:54:21

回答

3

问题1

  • merge方法必须在分离实体调用。
  • merge方法将返回合并对象附加到entityManager。

这是什么意思?

一旦你用来获取它的entityManager被关闭,实体就会被分离。 (即大部分时间是因为您在之前的交易中获取它)。

在你的第二个代码示例中:user被附加(因为你只是获取它),所以调用merge是没用的。 (顺便说一句:它不是getReference,而是find

在你的第一个样本中:我们不知道用户的状态(分离的实体与否?)。如果它是分离的,则调用merge是有意义的,但请注意merge不会修改其作为参数传递的对象。因此,这里是我的版本的第一个样本:

/** 
* @param user : a detached entity 
* @return : the attached updated entity 
**/ 
public User updateUserName(User user, String name) { 
    user.setName(name); 
    user.setChangeDate(new Date()); 
    return em.merge(user); 
} 

问题2

也许一些代码示例来解释你的意思由JPA处理程序可以帮助我们理解您的关注。无论如何,我会尽力帮助你。

如果你有一个持续的用户,你需要创建一个新的组,它与持久用户关联:

User user = em.find(User.class, userId); 
Group group = new Group(); 
... 
em.persist(group); 
user.addToGroups(group); 
group.addToUsers(user); //JPA won't update the other side of the relationship 
         //so you have to do it by hand OR being aware of that 

如果你有一个持续的用户和持久群组,你需要将它们联系起来:

User user = em.find(User.class, userId); 
Group group = em.find(Group.class, groupId); 
... 
user.addToGroups(group); 
group.addToUsers(user); 

一般考虑

最好关于所有这些的实践实际上取决于你管理事务(以及entityManager的生命周期)与对象的生命周期。

大部分时间:一个entityManager是一个非常短的时间生活对象。另一方面,你的业务对象可能活得更久,所以你将不得不调用合并(并注意合并不会修改在参数中传递的对象!!!)。

您可以决定在同一个事务中(即使用同一个entityManager)获取和修改您的业务对象:这意味着更多的数据库访问,并且出于性能原因,此策略通常必须与第二级缓存相结合。但在这种情况下,您不必调用合并。

我希望这个帮助。

+0

谢谢您的答复。关于我的问题1,是不是最简单的方法来设置我的领域像日期和新名称在我的方法调用JPA处理程序,只调用一个方法“updateUser(用户用户)”只是合并用户对象和保存所有更改,而不是为几个更新用例创建方法? – ManuPanu 2013-04-05 14:38:44

6
  1. 这取决于你想要达到的目标以及你想要合并的对象的起源有多少信息。首先,如果您在方法的第一行中调用em.merge(user),或者最后调用em.merge(user)并不重要。如果你使用JTA和CMT,你的实体将在方法调用结束时更新。唯一的区别是,如果你改变用户之前调用em.merge(user)你应该使用你的参数返回的实例,所以要么是:

    public void updateUserName(User user, String name) { 
        User managedUser = em.merge(user); 
        managedUser.setChangeDate(new Date()); 
        // no need of additional em.merge(-) here. 
        // JTA automatically commits the transaction for this business method. 
    } 
    

    public void updateUserName(User user, String name) { 
        user.setChangeDate(new Date()); 
        em.merge(user); 
        // JTA automatically commits the transaction for this business method. 
    } 
    

    现在有关更新实体。
    如果您只想更新实体中的一些明确定义的字段,请使用第二种方法,因为它更安全。您无法确定您的方法的客户端是否未修改实体的其他字段。因此,em.merge(-)也会更新它们,这可能不是您想要实现的。另一方面 - 如果您想接受用户所做的所有更改,并在您的示例中仅覆盖/添加一些属性(如changeDate),则第一种方法也可以(将整个实体合并到业务方法中)。真的取决于你的用例。

  2. 我想这取决于你的级联设置。如果您想在User实体更改时自动持续/合并所有Groups - 将它添加到用户的集合中是很安全的(类似于User#addGroup(Group g) { groups.add(g)})。如果您不想级联,则始终可以创建自己的方法,以便传播到关系的另一边,可能是这样的:User#addGroup(Group g),它会自动调用g.addUser(this);