简体   繁体   English

JAVA JPA更新相关实体

[英]JAVA JPA updating the related entities

I have a problem with updating related entities. 我在更新相关实体时遇到问题。

Let me start with a straightforward example. 让我从一个简单的例子开始。 Suppose I have a User 1:1 Profile relation. 假设我有一个User 1:1 Profile关系。

How can I update (replace) Profile entity which belongs to User ? 如何更新(替换)属于User的Profile实体?

I have tried the followings without success (both OneToOne relation has CascadeType=ALL property) 我尝试了以下失败的尝试(OneToOne关系都有CascadeType = ALL属性)

em.getTransaction().begin();

1.User.setProfile(Profile)
....
2.User.setProfile(Profile)
Profile.setUser(User)
.....
3.em.remove(User.getProfile())
User.setProfile(Profile)
Profile.setUser(User)

em.getTransaction().commit();

I'm totally confused with JPA, there are some useful example, but they are not about updating entities (just updating single values, raising salary etc ...) 我对JPA完全感到困惑,有一些有用的示例,但它们与更新实体无关(仅更新单个值,提高薪水等)。

I hope the suggested way will work on in case of 1:N relations as well. 我希望所建议的方法在1:N关系的情况下也能适用。

I always do em.merge(user); 我总是做em.merge(user); after updating entity. 更新实体后。 That will updated all related entities too, if you have appropriate cascading options. 如果您有适当的级联选项,这也会更新所有相关的实体。

Now, I know (heard) that entity is supposed to update database itself by the end of transaction, but I prefer having a straight call. 现在,我知道(听说)该实体应该在事务结束时更新数据库本身,但是我更喜欢直接打电话。 And frankly, I find the whole 'auto-updating entity' pattern to be more of a problem than advantage in real-world development. 坦率地说,我发现整个“自动更新实体”模式在现实世界开发中更多的是问题而不是优势。

It depends on what you want to do. 这取决于您想做什么。 If User and Profile are truly one-to-one, then the whole idea of replacing the whole Profile object with a different one is a little redundant. 如果User和Profile是真正一对一的,那么用一个不同的Profile对象替换整个Profile对象的整个想法有点多余。 If you are using a framework which retains the Persistence Context across the entire operation then you can just update the values in the Profile object and flush, as creating new objects will be a bit confusing because of the cascades. 如果使用的框架在整个操作中都保留了持久性上下文,则可以仅更新 Profile对象中的值并进行刷新,因为级联会导致创建新对象有些混乱。

However, if your framework does not keep the Persistence Context around, then you'll have detached entities that have been modified, and you must either use em.merge() or you can get the original entity ( em.find ) and copy the properties in. IMO, this is tedious, error prone, and unnecessary given a framework that uses JPA properly. 但是,如果您的框架没有保留Persistence Context,那么您将拥有已被修改的分离实体,您必须使用em.merge() 获取原始实体( em.find )并复制在IMO中,如果给定正确使用JPA的框架,这将很繁琐,容易出错且不必要。 It's much better to modify the objects in the Persistence Context and let the 'auto-update entity' thing do it's job (which obviously I'm a big fan of). 最好在持久性上下文中修改对象,然后让“自动更新实体”来完成任务(显然,我非常喜欢)。 It takes a little getting used to, but once you get it, you'll never want to go back. 这需要一点时间来适应,但是一旦您习惯了,就永远不会回头。

In any case, all the changes will be written out to the JDBC connection when em.flush() is called, and the pending changes in the connection will be committed when the transaction completes. 无论如何,在调用em.flush()时,所有更改都将写到JDBC连接中,并且在事务完成时将提交连接中的未决更改。

How can I update (replace) Profile entity which belongs to User? 如何更新(替换)属于用户的Profile实体?

Since your association is bi-directional, you have to manage both sides of the link between User and Profile . 由于关联是双向的,因此您必须管理UserProfile之间的链接的两端。 So "changing" a user's profile would require something like this: 因此,“更改”用户的个人资料将需要以下内容:

User user = em.find(User.class, key);

Profile profile = new Profile();
...
user.setProfile(profile);
profile.setUser(user);

em.getTransaction().commit(); 

With the JPA implementation I used, the following query have been performed for the above code: 使用我使用的JPA实现,已经对上述代码执行了以下查询:

INSERT INTO CPROFILE (ID) VALUES (?)
    bind => [2]
UPDATE CUSER SET CPROFILE_ID = ? WHERE (ID = ?)
    bind => [2, 1]

I removed the CascadeType ALL, and everything works as we expected, here comes the code 我删除了CascadeType ALL,一切都按预期运行,代码如下


......................... CPROFILE
@Entity
public class CProfile {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Key id;
        private String phone;

    @OneToOne(mappedBy="profile")
    private CUser User;

......................... CUSER @Entity public class CUser { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Key id; private String email;

@OneToMany(mappedBy="user")
private List<CPossibility> Possibilities = new ArrayList<CPossibility>();

@OneToOne 
@JoinColumn(name="cprofile_id") 
private CProfile profile;   

......................... CREATE ... CUser User = em.find(CUser.class, UserId_); ...
em.getTransaction().begin(); try { Profile_.setUser(User); User.setProfile(Profile_);

        em.persist(Profile_);

        em.getTransaction().commit();
    }
    catch(Exception e){GAEHelper.getLogger().warning("Exception:"+e.getMessage()+" "+e.getCause());}        
    finally {
        if (em.getTransaction().isActive()) {
            em.getTransaction().rollback();
        }
    }

    em.close();

    return true;
}

......................... UPDATE
... CUser User = em.find(CUser.class, UserId_); ... em.getTransaction().begin(); try { em.remove(User.getProfile());

        Profile_.setUser(User);             
        User.setProfile(Profile_);

        em.persist(Profile_);
        em.getTransaction().commit();
    }

Thanks Guys ! 多谢你们 !

cscsaba 卡萨巴

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM