来自服务的实体和对象之间的关系

问题描述

我正在尝试在我的 Book 实体和我通过服务检索的语言列表之间建立关系。 在我的数据库中,每本书都有一个:ID、TITLE、CATEGORY_ID (FK)、LANG_ID

Book.java:

@Entity
@Table(schema = Constants.SHEMA,name = "Book")
public class Book implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private long id;
 
    @Column(name = "TITLE")
    private String title;
 
    @ManyToOne(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
    @JoinColumn(name = "CATEGORY_ID")
    private Category category;
 
    private Language language; // -> The Column associated in the database is Long LANG_ID
 
}

类别.java:

@Entity
@Table(schema = Constants.SHEMA,name = "Category")
public class Category implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private Long id;
 
    @Column(name = "NAME")
    private String name;
}

语言.java:

public class Language implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    private Long id;
 
    private String name;
}
 

我理解 Book 和 Category 之间的关系,因为它们都是我数据库中的表。但是,Language 是我从服务中获得的东西,并没有保留在我的数据库中。 我得到的语言只是语言的 ID 和名称

我的问题是:为了将语言 ID 链接到我的 LANG_ID(我的 Book 表中语言的 ID),我应该为 Language 编写什么注释(ManyToOne、Entity...)?我也应该把它放在我的 persistence.xml 中吗?我尝试了几个,但似乎效果不佳。

非常感谢

解决方法

首先,您是否考虑在您的数据库中存储语言?我的意思是语言大体相同,不会经常更改,您也可以将它们存储在属性文件中并在运行时读取它们以备后用。

无论如何,我认为你应该:

  • 首先从外部系统语言获取
  • 存储在变量/内存缓存中(例如 Map,您可以在其中存储 id 和 name)
  • 从数据库中读取数据
    • 对于你所做的每一行
      • 读取书籍语言 ID,读取缓存,获取您需要的数据

如果您无法更改模型,只需将 dto 与您的实体和语言一起使用即可

,

我认为将持久化数据与非持久化数据混合在一起不是一个好习惯,因为这会导致其他意外问题。无论如何,你可以尝试这样的事情:

@Entity
@Table(schema = Constants.SHEMA,name = "Book")
public class Book implements Serializable {

  private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "ID")
  private long id;

  @Column(name = "TITLE")
  private String title;

  @ManyToOne(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
  @JoinColumn(name = "CATEGORY_ID")
  private Category category;

  @Column(name = "LANG_ID")
  private Integer langId;

  @Transient
  private Language language;

  @PostLoad
  public void loadLanguage() {
      // get the language data here
  }

}

language 字段没有数据库表,因此您不能使用任何映射注释。来自 Java EE 文档:

public @interface Transient

Specifies that the property or field is not persistent. It is used to annotate a property or field of an entity class,mapped superclass,or embeddable class.

    Example:

    @Entity
    public class Employee {
        @Id int id;
        @Transient User currentUser;
        ...
    }

@PostLoad 注释声明了一个在实体加载后要调用的方法:

public @interface PostLoad

Specifies a callback method for the corresponding lifecycle event. This annotation may be applied to methods of an entity class,a mapped superclass,or a callback listener class.