2010-06-27 201 views
1

我在更新相关实体时遇到问题。JAVA JPA更新相关实体

让我从一个简单的例子开始。 假设我有一个用户1:1配置文件关系。

如何更新(替换)属于用户的配置文件实体?

我曾尝试没有成功如下(均为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(); 

我和JPA完全糊涂了,也有一些有用的例子,但他们不是更新的实体(只是更新单个值,提高薪水等......)

我希望建议的方式也适用于1:N关系的情况。

+0

我不知道你是否可以这样做。找到Profile obj并为其分配一个新对象。 profile = new Profile(...) – 2015-08-12 00:14:56

回答

0

我在更新实体后总是做em.merge(user);。如果您有适当的级联选项,那么也会更新所有相关实体。

现在,我知道(听说)实体应该在事务结束时更新数据库本身,但我更喜欢直接调用。坦率地说,我发现整个“自动更新实体”模式比实际开发中的优势更成为一个问题。

+0

除非你有分离的实体,否则你不应该使用'em.merge()'。当实体管理器被刷新时,持久化上下文中的所有实体都会自动更新,一些(IMO不灵活的)框架在每次事务结束时强制执行。 – 2010-06-27 18:52:48

+0

@Joshua我不应该,但这种方式,它的工作:) – 2010-06-27 18:58:14

+0

你是不是这个意思? Profile.setUser(User); User.setProfile(Profile); em.merge(User); 或 User.setProfile(Profile); em.merge(User); 他们不工作......新的配置文件被保存,但它不能取代旧配置文件。 我错了什么? – cscsaba 2010-06-27 19:09:02

0

这取决于你想要做什么。如果用户和配置文件真实地为一对一,那么将整个配置文件替换为另一个对象的整个想法有点多余。如果您使用的是框架,保持整个操作的持久化上下文,那么你可以只更新档案对象并刷新值,如创建新的对象会因为级联的有点混乱。

但是,如果你的框架不会保留持久化上下文的身边,那么你就必须分离的实体已经被修改,你必须使用em.merge()你可以得到原来的实体(em.find)并复制属性。IMO,这是乏味的,容易出错的,并且没有必要给出一个适当使用JPA的框架。这是更好的修改对象的持久化上下文,让“自动更新实体”的事情做的工作(这很明显,我的大风扇)。这需要一点习惯,但一旦你得到它,你永远不会想回去。

在任何情况下,当调用em.flush()时,所有更改都将写入JDBC连接,并且在事务完成时将提交连接中的挂起更改。

+0

我想我需要在互联网上的某个地方的例子。 在GAE上使用JPA(我想使用:) – cscsaba 2010-06-27 19:19:58

+0

你提到的几个术语在实践中不太明确,这将是一个很好的例子。 我复制粘贴在我的实体的源代码上面。 – cscsaba 2010-06-27 19:31:42

0

如何更新(替换)属于用户个人资料的实体?

由于您的关联是双向的,你必须UserProfile之间的管理链接的两侧。因此,“改变”一个用户的配置文件将需要是这样的:

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

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

em.getTransaction().commit(); 

随着JPA实现我所用,下面的查询已经被上面的代码执行:

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

你好帕斯卡,我已经试过你提到的这种方式没有成功,我不知道什么是错的。 我要再试一次,谢谢 并感谢大家! – cscsaba 2010-06-28 07:47:53

+0

@ cscsaba242:这很奇怪。但我不是GAE/J JPA“支持”的专家,也许有一些我不知道的行为的具体细节。 – 2010-06-28 14:13:58

0

我删除了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; 私人字符串电子邮件;

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

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

......................... CREATE ... CUser用户= em.find(CUser.class,UserId_ ); ...
em.getTransaction()。begin(); 尝试 { 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用户= em.find(CUser.class,用户名_); ... em.getTransaction()。begin(); 尝试 em.remove(User.getProfile());

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

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

谢谢你们!

cscsaba