Search code examples
javajpajava-ee-6

Relation between Entity and Object from service


I'm trying to make a relation between my Book entity and a list of languages that I retrieve through a service. In my database, each book has a: 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
 
}

Category.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;
}

Language.java:

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

I understood the relation between Book & Category as both of them are tables in my database. However, Language is something that I get from a service and isn't persisted in my database. The languages I get are just an ID and a Name for the language.

My question is: In order to link the language ID to my LANG_ID (the ID of the language in my Book table), what annotation (ManyToOne, Entity, ...) should I write for Language? Should I also put it in my persistence.xml ? I tried a couple but it seems like it's not working well.

Thank you very much


Solution

  • I don't think it is good practice to mix persisted data with non-persisted data as it can cause other unexpected problems. Anyway you can try something like this:

    @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
      }
    

    }

    The language field has no database table, so you cannot use any mapping annotation. From the Java EE docs:

    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;
            ...
        }
    

    The @PostLoad annotation declares a method to be called after the entity is loaded:

    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.