在Hibernate中,如何将多个类映射到一个表?

7
从我的研究来看,似乎不太可能实现,但这是我的用例。
我有一个名为user的表,其中包含一个地址id。
我想将UserReference和User类映射到这个表,其中UserReference不包含Address对象(以节省SQL连接时间),而User类包含Address对象(以防需要)。
我不能使用子类,因为它需要一个连接表,而且我也不能只定义两个单独的类,因为get()似乎会返回每一行的两倍(一个是User,一个是UserReference)。
有人知道我该如何处理吗?
我想我应该努力更好地解释一下自己。
public class UserReference {
    private int id;
    private String name;
}

public class User extends UserReference {
    private Address;
}

我想要同时映射UserReference和User,这样我就可以在只需要基本信息时查询UserReference,而在需要完整对象时查询User。
我知道可以将Address设置为延迟加载,但是我的系统是两层结构,一旦通过这些层,所有对象都会被取消代理。
编辑:
也许我的问题表达得太含糊了,但根据回答来看,似乎很难实现我想要的。不管怎样,还是谢谢大家。

将同一张表映射到多个实体是完全可以的。但是,如果你试图通过这种方法来解决“取消代理”问题(我猜你指的是遍历整个对象图?),那么在未来你会遇到很大的麻烦,特别是当你有更复杂的对象关系,并且在不同的函数中需要不同的关系组合时。 - Adrian Shum
嗯,你能进一步解释为什么这可能会成为未来的问题吗? - kennyg
如果您的系统继续增长,您可能会有一个实体A与B、C、D和E之间存在关系。而且,您可能会有不同的函数,其中函数1只需要A,函数2需要A + B,函数3需要A + C + D,函数4需要A + C + E等等。通过使用您的方法,您将需要不同形式的A实体来应对不同函数的使用。这将成为一个维护噩梦。 - Adrian Shum
3个回答

5
你的问题对我来说不太清楚,但我会尝试根据我的理解回答。这取决于你想要持久化什么以及你想要作为Java实体。考虑你想要表示用户类与数据库表,即将用户表示为JPA实体。现在你可以创建一个嵌入式类,该类将成为另一个类的一部分。因此,你可以将地址类映射到用户实体中,并使用@Embeddable注释将地址类作为嵌入式类。包com.thejavageek.embeddabledemo;
import javax.persistence.Embeddable;

@Embeddable
public class Address {

    private String area;
    private String city;
    private String pincode;

    public String getArea() {
        return area;
    }

    public void setArea(String area) {
        this.area = area;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getPincode() {
        return pincode;
    }

    public void setPincode(String pincode) {
        this.pincode = pincode;
    }

}

你可以像下面这样嵌入这个可嵌入的类

package com.thejavageek.embeddabledemo;

import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.TableGenerator;

@Entity
public class Person {

    @TableGenerator(name = "person_gen", table = "id_gen", pkColumnName = "gen_name", valueColumnName = "gen_val", allocationSize = 100)
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "person_gen")
    private String idperson;
    private String name;

    @Embedded
    private Address address;

    public String getIdperson() {
        return idperson;
    }

    public void setIdperson(String idperson) {
        this.idperson = idperson;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

}

4

UserReference.java

@Entity
@DiscriminatorColumn(name = "type")
@DiscriminatorValue(value = "UserReference")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class UserReference extends BaseEntity {

    private String name;
}

User.java

@Entity
@DiscriminatorValue(value = "User")
public class User extends UserReference {
    @OneToOne
    @JoinColumn(name = "address_id")
    private Address address;

}

原帖作者真的需要继承吗? - Prasad Kharkar

1

我想你的意思是你有一个类似下面的表格:

USER
- USER_ID
- USER_NAME
- ADDRESS_ID

and

ADDRESS
- ADDRESS_ID
- ADDRESS_DETAIL

像这样吗?

你想要两个 User 实体,其中一个包含对 Address 的引用,而另一个没有(因此可以节省 SQL 连接时间),我的理解正确吗?

如果是这样,你不需要这样做。

只需拥有一个 User 实体,并将其 Address 关系设置为 LAZY 获取即可。

如果在任何函数中需要 User 中的 Address,请执行联接获取。

例如:

@Entity
public class User {
    @Id
    private Long id;

    private String name;

    @ManyToOne(fetch=FetchType.LAZY)
    private Address address;
}

在这种情况下,所有正常的User检索将不会引起对Address表的任何连接。但是可以灵活地执行类似以下操作:
from User u left join fetch u.address where u.name like 'blabala'

延迟获取会起作用,但我的系统是多层的,因此一旦它通过各个层级,就期望已经获取了Address对象。 - kennyg
这不会是个问题。我已经做了多年同样的事情。你有两个选择:1. 确保对于需要地址的函数,在将对象返回事务边界之前,你已经获取了地址(通过join fetch等方式)。或者,2. 在从txn边界返回之前构造一个非持久化相关值对象。还有其他方法,比如在视图中打开会话或使用jpa实现来允许延迟获取而不需要活动txn。但我个人不喜欢那些方式。 - Adrian Shum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接