【问题标题】:Eclipse hibernate pojo generation include foreign keysEclipse hibernate pojo 生成包括外键
【发布时间】:2016-03-21 23:25:41
【问题描述】:

我一直在关注使用 hibernate 从 mysql 数据库生成 pojos 的优秀指南。可以在此处找到指南以供参考: Generate pojos with hibernate

当存在外键时,我得到的 pojo 具有嵌入其他对象的字段。例如,用户有地址。 Hibernate 正在生成如下内容:

public class User(){
 private String name;
 private Integer uid;
 private Address address;
}

不过,我有一个问题,我希望类实际上包含外键值。例如,我希望 User 对象具有对应于 addressId 的数据库字段的类字段。所以,我希望对象实际上看起来像这样:

public class User(){
 private String name;
 private Integer uid;
 private Integer addressId;
 private Address address;
}

有谁知道如何修改休眠代码生成过程,以便将外键值作为字段包含在对象上?

更新: 我发现了一个 SO 帖子,它描述了如何忽略外键关系并将外键作为类字段:How to ignore foreign keys?

这里的问题是我想要两者。我不想忽视这些关系。我希望它们代表,但我也想要实际的外键值。

更新:

让我更具体地说明我为什么想要这个解决方案。我们正在尝试序列化这些休眠对象。现在,我们有很多不同的休眠 pojo 正在被逆向工程。我们不想为每个类手动编写序列化例程。如果我们遵循“只需手动编写对嵌入对象的外键字段的访问方法”的约定,我们将不得不这样做。此外,即使我们这样做,pojo 仍然不知道外键的字段叫什么。相反,我们使用带有类型适配器的 gson。

使用 gson,我们正在序列化 pojo 上的所有字段,而只是忽略包含休眠对象的字段。当然,问题是我们没有外键字段。我们在这里需要一些信息,以便一般地序列化任何休眠 pojo。我们需要知道:

  1. 外键字段名
  2. 外键字段值

【问题讨论】:

    标签: java eclipse hibernate foreign-keys hibernate-tools


    【解决方案1】:

    您的方法违反了 Hibernate 约定。因为 Hibernate 使用反射,所以约定对于 Hibernate 完成它的工作是必不可少的。因此,我怀疑 Maouven 的“遵循惯例”方法是最简单的。但是,如果不可协商,您有两种选择。

    您的第一个选择是添加一个临时 getter,以公开 getAddressId() 函数。

    public class User() {
        private String name;
        private Integer uid;
        private Address address;
    
        // Getters, setters...
    
        @Transient
        public boolean getAddressId() {
            address.getId();
        }
    }
    

    您的第二个选择是添加一个数据访问层以将您自己的约定强加于 Hibernate 对象之上。这一抽象层将不受 Hibernate 约定的约束。这样一来,您的 POJO 将由 DAO (Data Access Objects) 包装,您可以根据需要进行设计。

    更新:

    鉴于您的特殊情况,请考虑修改您的序列化步骤。 GSON 通常不能使用瞬态方法,但是有一个扩展可以做到this,如图here。

    另一种解决方案是使用反射以您想要的方式复制对象,然后使用 GSON 序列化复制的对象。

    【讨论】:

    • 假设我们使用了 getAddressId() 方法。系统仍然不知道用于序列化目的的外键的字段名称是什么。我写了一个更新来解释我们的具体用例,只是为了帮助理解上下文。令我惊讶的是,很大比例的 hibernate 社区没有遇到这个确切的问题。人们肯定不会坐下来手动编写/维护数十个(如果不是数百个)序列化例程吗?
    • 关于 DAO 包装器,我将如何将外键字段名称和值放入这样的对象中?这里也有类似的问题,只是上一层而已。
    • 感谢您的更新。就个人而言,我们确实有单独的 POJO 可以序列化,并且我们有填充它们的复制构造函数。这避免了两个固执己见的库尝试对同一个对象使用反射的问题。
    • DAO 包装器以类似的方式避免了该问题。额外的层允许每个自以为是的库以它想要的方式使用反射。这又不是自动化的,所以它可能对您来说不是一个好的解决方案。
    • 关于您的更新,这是否需要为每个类编写一个自定义序列化程序,然后使用 gson 注册它?如果是这样,这将不会更易于维护。
    【解决方案2】:

    您的方法会导致班级数据出现冗余。在 Hibernate 生成的第一组代码中,您可以从 User Class 的 Address 属性中获取所需的 addressId :

    yourUser.getAddress().getAddressId();
    

    【讨论】:

    • 我确实意识到相同的信息被编码了两次,一次作为外键,一次作为唯一 ID。我发现在对象上保存数据的便利性值得以非常小的内存占用为代价。明确提到外键可以更容易地编写通用方法。
    【解决方案3】:

    两种可能(理论上)解决方案,但需要通过 Hibernate Tools 进行逆向工程后手动重构:

    我使用注释只是为了简洁

    1) 使用映射公开列:

    @Entity
    class User
    {
        @Id
        @Column
        private Integer uid;
    
        @Column
        private String name;
    
        @Column(name = "ADDRESS_ID", insertable = false, updatable = false)
        private Integer addressId;
    
        @ManyToOne
        @JoinColumn(name = "ADDRESS_ID")
        private Address address;
    }
    

    2) 使用@Transient + @PostLoad:

    @Entity
    class User
    {
        @Id
        @Column
        private Integer uid;
    
        @Column
        private String name;
    
        @Transient
        private Integer addressId;
    
        @ManyToOne
        @JoinColumn(name = "ADDRESS_ID")
        private Address address;
    
        @PostLoad
        public void postLoad()
        {
            addressId = Optional.ofNullable(address).map(Address::getId).orElse(null);
        }
    }
    

    另一种解决方案可能是使用 JAXB 的 JSON 编组器:

    @XmlRootElement
    class User
    {
        @XmlID
        private Integer uid;
    
        private String name;
    
        @XmlIDREF
        private Address address;
    }
    

    您可以找到快速入门here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-01
      • 2010-09-16
      • 1970-01-01
      • 1970-01-01
      • 2012-01-13
      • 2011-12-19
      • 2016-08-14
      • 2011-12-05
      相关资源
      最近更新 更多