【问题标题】:update hibernate JPA更新休眠 JPA
【发布时间】:2011-06-12 15:08:35
【问题描述】:

在休眠 JPA 中,我如何更新对象? 我有一个具有两个属性的项目实体。 projectid 和项目名称。 这里 projectid 是主键。现在在我的更新方法中,我应该能够修改属性 projectid 和 projectname。查询应该如下所示。

update PROJECT set ID='123',NAME='Intel' where ID='122'

我想将 project_id 分配给 user_id。

project_table
-------------
project_id  project_name  
-------------------------  
LK987       LockSystem  
MK876       MockSystem      


user_project_table
---------------------  
user_id        project_id  
--------------------------  
12343       LK987  
12344       MK876  
12343       TK656  
12675       TK656  

【问题讨论】:

    标签: hibernate jpa-2.0


    【解决方案1】:

    停止思考 SQL,开始思考EntityManager 项目 p = entityManager.find(Project.class, 122); p.setId(123); p.setName("英特尔"); entityManager.merge(p);

    也就是说,几乎 总是选择change an entity's primary key是错误的。

    您为什么要更改实体的身份?您还需要更新指向它的其他表中的所有外键。好像很痛苦,没有收获。您最好将其设为“业务密钥”(普通属性)并使用更永久的代理密钥。

    如果您真的需要能够更改项目的 ID 号,则应将主键更改为自动递增的数字。实体看起来像这样:

    @Entity
    public class Project
    {
        @Id @GeneratedValue
        private int id;
        private int projectId;
        private String projectName;
    
        // getters and setters
    }
    


    因此您希望将项目与用户相关联。

    您可以在项目 id(一个字符串,如 "LK987")作为主键的情况下执行此操作(到目前为止,我相信您知道您不应该更改它) - 或者您可以使用单独的自动增量 @ 987654335@ 作为 id。由你决定;我个人的偏好是自动增量方法,因此您以后不必担心。

    您要做的是在Project 实体和User 实体之间建立关系。您应该存储 entity 字段(用于一对一、一对多或多对一映射)或实体集合(用于一对一映射),而不是存储外键字段。多、多对一或多对多映射)。如果我了解您的需求:

    • 每个用户可以有多个项目,每个项目可以有多个用户(这样映射就是多对多)
    • 用户了解项目,项目也可能了解用户(因此映射是双向的)。我假设User 是关系的所有者,Project 是反面。

    这意味着您将使用@ManyToMany 注释,并指定@JoinTable 以及要使用的@JoinColumns。

    用户实体类

    @Entity
    public class User
    {
        @Id @GeneratedValue
        int id;  // the PK for user entities
    
        @ManyToMany
        @JoinTable(
            name="user_project_table",
            joinColumns=@JoinColumn(name="user_id"),
            inverseJoinColumns=@JoinColumn(name="project_id"))
        Set<Project> projects;
    
        // snip...
    }
    

    项目实体类

    @Entity
    public class Project
    {
        @Id @GeneratedValue
        int id;
        String projectId;
        String projectName;
    
        @ManyToMany(mappedBy="projects")
        Set<User> users;
    
        // snip...
    }
    

    注意我们如何使用成熟的实体类,而不仅仅是外键。

    来自The Java EE 6 Tutorial的进一步阅读:

    【讨论】:

    • +1 表示答案的结尾。此刻的开始有点狡猾。
    • 嗨,马特。感谢您的信息。我想将项目 ID 分配给用户 ID。如何将项目 ID 分配给用户 ID?我应该分配哪一个 project_id 或自动增量生成的 id?我如何设计这两个表并且项目 id 可能是字符串的类型。对我来说,我应该可以肯定地修改 project_id,因为如果用户可能输入错误的 project_id,并且如果他/她需要稍后更改 project_code,它应该对编辑选项有所帮助。
    • 当您说“我想将projectid 分配给userid”时,您的意思是您希望能够将项目与用户相关联吗?至于“我应该分配哪个”,您是在询问更改project_id 的值还是自动增量ID? 从不。改变。这。基本的。键。
    • 是的,我想将项目与用户相关联。在那种情况下,它如何在用户和项目之间建立关系?如果我想建立关系,我需要将 project_id 定义为 PK。所以这个 PK 将是用户表中的 FK,用于找出与用户关联的项目数量。虽然我们正在谈论更新项目ID,但我完全混淆了设计方式。请让我明白。我明白PK永远不应该改变。
    • 好的,我跟着。有比担心外键更好的方法。还记得我回答的第一句话吗?它仍然适用。在 JPA 中,您可以/应该将存储外键的字段替换为存储实体(或实体集合)的字段。我正在相应地编辑我的答案,但基本上你需要了解@OneToOne 和/或@OneToMany。每个用户可以只有一个项目,还是每个用户可以有多个项目?
    【解决方案2】:

    如果项目 id 是对象的主键和标识符,则永远不要更改它。主键的改变意味着表示的对象改变为完全不同的东西。

    JPA 假定主键是固定的。读取、更新和删除操作通过它的 id 识别有问题的对象。如果您更改对象的 id 并执行更新,JPA 要么更新一些完全不同的对象(这可能导致异常),要么根本找不到要更新的对象。

    为了强调这一点,JPA 规范禁止更改主键。 Hibernate 也可以从任何生成的更新语句中排除主键。见JSR-317第28页

    其主键的值唯一 标识一个实体实例 持久性上下文和 EntityManager 操作如所述 在第 3 章,“实体操作”中。这 应用程序不得更改该值 的主键(这包括不更改作为主键的可变类型的值或复合主键的属性)。行为 如果发生这种情况,则未定义(实现可以但不是必须抛出异常。可移植应用程序不得依赖任何此类特定行为)。

    要达到预期的效果,您应该删除旧对象并创建一个新对象。

    【讨论】:

      猜你喜欢
      • 2016-01-19
      • 2013-06-19
      • 2011-06-25
      • 1970-01-01
      • 2012-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-25
      相关资源
      最近更新 更多