简体   繁体   English

Hibernate映射连接在常量表的一列上

[英]Hibernate mapping join on one column of constants table

I have 2 tables, the first one is quite variable, the second one contains only constants: 我有2个表,第一个是变量很大,第二个只包含常量:

USER.ID   USER.NAME   USER.USER_TYPE (FK on USER_TYPE.ID)
INT       VARCHAR(64) INT(1)
----------------------------------
1         Alex        3
2         Jane        1
3         Carl        3

USER_TYPE.ID   USER_TYPE.VALUE
INT(1)         VARCHAR(64)
------------------------------
1              PENDING
2              REGISTERED
3              BANNED
4              ACTIVE

The foreign key USER.USER_TYPE is required and refering to a primary key USER_TYPE.ID in table USER_TYPE (one-to-one relation). 外键USER.USER_TYPE是必需的,并且USER_TYPE.IDUSER_TYPE的主键USER_TYPE (一对一关系)。 Here is my mapping in Hibernate. 这是我在Hibernate中的映射。

User.java User.java

@Entity
@Table(name = "USER")
public class User {

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

    @Column(name = "NAME")
    private String name;

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)   
    @JoinColumn(name = "USER_TYPE") 
    private UserType userType;
}

UserType.java UserType.java

@Entity
@Table(name = "USER_TYPE")
public class UserType {

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

    @Column(name = "VALUE")
    private String value;
}

My goal is to keep the enumerated values in the database. 我的目标是将枚举值保留在数据库中。 How to map UserType 's value instead of id to User and validate it? 如何将UserType的值而不是id映射到User并验证它? I want to pass the constant VALUE to the String instead of its ID. 我想将常量VALUE传递给String而不是它的ID。

private String userType;

The expected result of the first user would be: 第一个用户的预期结果是:

User[id=1, name=Alex, userType=Banned]
User[id=2, name=Jane, userType=Pending]
User[id=3, name=Carl, userType=Banned]

My attempt was to use this annotation on definition of table twice with both colums switched 我的尝试是在两个colums切换时对表的定义使用此注释

@SecondaryTable(name="USER_TYPE", 
    pkJoinColumns={@PrimaryKeyJoinColumn(name="ID", referencedColumnName="USER_TYPE")}
)

and get the VALUE with 并获得VALUE

@Column(table="USER_TYPE", name="VALUE")
private String UserType;

however it leads to the error 但它会导致错误

Unable to find column with logical name: USER_TYPE in org.hibernate.mapping.Table(USER) and its related supertables and secondary tables 无法找到具有逻辑名称的列:org.hibernate.mapping.Table(USER)中的USER_TYPE及其相关的supertable和辅助表

First you need to change the relation from @OneToOne to @ManyToOne as UserType can be used by one or many User and User can have one and one UserType . 首先,您需要将关系从@OneToOne更改为@ManyToOne,因为UserType可以由一个或多个UserUser可以拥有一个和一个UserType

Secondly use referencedColumnName which references : 其次使用引用的 referencedColumnName:

The name of the column referenced by this foreign key column. 此外键列引用的列的名称。

So User entity will be: 所以User实体将是:

@Entity
@Table(name = "USER")
public class User {

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

    @Column(name = "NAME")
    private String name;

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)   
    @JoinColumn(name = "USER_TYPE", referencedColumnName = "VALUE") 
    private UserType userType;    
}

In UserType you should apply a unique constraint using @NaturalId to value field + do not provide its setter, to prevent duplicate values as It may lead to inconsistency: UserType您应该使用@NaturalId将唯一约束应用于value字段+不提供其setter,以防止重复值,因为它可能导致不一致:

@Entity
@Table(name = "USER_TYPE")
public class UserType {

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

    @NaturalId 
    @Column(name = "VALUE")
    private String value;
}

Hope it solves the issue! 希望它能解决这个问题!

Enumerations could be simpler: 枚举可能更简单:

enum UserType {
    PENDING,
    REGISTERED,
    BANNED,
    ACTIVE
}

@Entity
@Table(name = "USER")
public class User {

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

    @Column(name = "NAME")
    private String name;

    @javax.persistence.Enumerated
    private UserType userType;
}

If you really need separated table and @OneToOne relation, you can use @Formula from Hibernate: 如果你真的需要分离表和@OneToOne关系,你可以使用Hibernate的@Formula:

@Formula("(select ut.value from user_type ut where ut.ID = USER_TYPE)")
private String userType;

For this really special requirement you could use SecondaryTable annotation. 对于这个非常特殊的要求,您可以使用SecondaryTable注释。 That is, you don't need UserType entity, but declare attribute userType as String in User entity with column mapping to the secondary table "USER_TYPE". 也就是说,您不需要UserType实体,但在User实体中将属性userType声明为String,并将列映射到辅助表“USER_TYPE”。

First of all, I suggest you use ManyToOne relation. 首先,我建议你使用ManyToOne关系。 and Not CascadeType.ALL if you are not planning update or delete on USER_TYPE table. 和不CascadeType.ALL如果你不打算更新或删除USER_TYPE表。

If you do not need adding new UserTypes frequently use enum for it. 如果您不需要经常添加新的UserTypes使用枚举。 It will just work as you want. 它会按你的意愿工作。

Second solution: As long as fetch = FetchType.EAGER you can add A transient field and return value of UserType in getter. 第二种解决方案:只要fetch = FetchType.EAGER ,就可以在getter中添加一个瞬态字段并返回UserType值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM