使用Hibernate JPA在列中存储对象

时间:2010-01-23 02:43:49

标签: java hibernate serialization orm jpa

是否可以仅使用一个表来存储以下内容?现在,hibernate将做的是创建两个表,一个用于家庭,一个用于人。我想将familymembers对象序列化到数据库的列中。

@Entity(name = "family")
class Family{

    private final List<Person> familyMembers;

}

class Person{

   String firstName, lastName;
   int age;

}

4 个答案:

答案 0 :(得分:13)

这是一个可怕的设计,我真的不推荐它(你应该创建另一个表),但它是可能的。

首先,您需要使用byte[]属性来保存将存储在数据库中的BLOB中的人员列表的序列化版本。所以用@Lob注释它的getter(我会让getter和setter private不暴露它们)。然后,公开“假”getter和setter以从List<Person>返回或设置byte[]。我在下面的示例中使用Commons Lang中的SerializationUtils(如果您不想导入此库,则提供自己的帮助程序类),以便快速序列化/反序列化byte[]。不要忘记用@Transcient标记“假”getter,否则Hibernate将尝试创建一个字段(并且因为它无法确定List的类型而失败)。

@Entity(name = "family")
class Family implements Serializable {

    // ...

    private byte[] familyMembersAsByteArray;

    public Family() {}

    @Lob
    @Column(name = "members", length = Integer.MAX_VALUE - 1)
    private byte[] getFamilyMembersAsByteArray() { // not exposed
        return familyMembersAsByteArray;
    }

    private void setFamilyMembersAsByteArray((byte[] familyMembersAsByteArray() { // not exposed
        this.familyMembersAsByteArray = familyMembersAsByteArray;
    }

    @Transient
    public List<Person> getFamilyMembers() {
        return (List<Person>) SerializationUtils.deserialize(familyMembersAsByteArray);
    }

    public void setParticipants(List familyMembers) {
        this.familyMembersAsByteArray = SerializationUtils.serialize((Serializable) familyMembers);
    }
}

不要忘记制作PersonSerializable并添加真实serialVersionUID(我只是在这里显示默认值):

public class Person implements Serializable {

   private static final long serialVersionUID = 1L;

   // ...

   private String firstName, lastName;
   private int age;

}

但是,让我坚持,这是一个可怕的设计,它将非常脆弱(改变Person可能需要“迁移”BLOB的内容以避免反序列化问题,这将变得痛苦。你应该真的重新考虑这个想法并使用另一个表来代替Person(或者我不明白为什么你使用数据库)。

答案 1 :(得分:3)

@Type(type = "serializable")
private List<Person> familyMembers;

如果你不能使用hibernate注释,试试这个:

@Lob
private Serializable familyMembers;

public List<Person> getFamilyMembers(){
    return (List) familyMembers;
}

public void setFamilyMembers(List<Person> family){
    familyMembers = family;
}

答案 2 :(得分:1)

使用@Column为该属性添加注释,并将类型定义为ArrayList,而不只是List。并Person实施Serializable

但是只有在你的动机非常明确的情况下才应该这样做,因为在一些非常罕见的情况下这是正确的解决方案。正如Pascal所说,如果你不得不改变Person,你会感到头痛。

答案 3 :(得分:0)

您可以创建接受/返回序列化表单的pseudoproperty(getter和setter),并使用familyMembers注释@Transient。这还需要为所有其他属性注释getter而不是字段。