Хранение объектов в столбцах с использованием Hibernate JPA - PullRequest
8 голосов
/ 23 января 2010

Можно ли хранить что-то вроде следующего, используя только одну таблицу? Сейчас hibernate создаст две таблицы: одну для семей и одну для людей. Я хотел бы, чтобы объект familymembers был сериализован в столбец в базе данных.

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

    private final List<Person> familyMembers;

}

class Person{

   String firstName, lastName;
   int age;

}

Ответы [ 4 ]

13 голосов
/ 23 января 2010

Это ужасный дизайн, и я действительно не рекомендую его (вы должны просто создать другую таблицу), но это возможно.

Во-первых, вам нужно будет использовать атрибут byte[] для хранения сериализованной версии списка людей, который будет сохранен в BLOB-базе данных. Так что пометьте его как getter с @Lob (я бы сделал getter и setter private, чтобы не выставлять их). Затем откройте «поддельные» методы получения и установки для возврата или установите List<Person> из byte[]. Я использую SerializationUtils от Commons Lang в приведенном ниже примере (укажите собственный класс помощника, если вы не хотите импортировать эту библиотеку) для сериализации / десериализации на лету в / из byte[]. Не забудьте пометить «поддельный» метод получения с помощью @Transcient, иначе 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);
    }
}

Не забудьте создать Person класс Serializable и добавить реальное serialVersionUID (я просто показываю здесь значение по умолчанию):

public class Person implements Serializable {

   private static final long serialVersionUID = 1L;

   // ...

   private String firstName, lastName;
   private int age;

}

Но, позвольте мне настаивать, это ужасный дизайн, и он будет очень хрупким (изменение Person может потребовать «переноса» содержимого BLOB во избежание проблем с десериализацией, и это станет болезненным. эта идея и использовать другую таблицу для Person вместо этого (или я не понимаю, почему вы используете базу данных).

3 голосов
/ 23 января 2010
@Type(type = "serializable")
private List<Person> familyMembers;

, если вы не можете использовать спящие аннотации, попробуйте это:

@Lob
private Serializable familyMembers;

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

public void setFamilyMembers(List<Person> family){
    familyMembers = family;
}
1 голос
/ 23 января 2010

Аннотируйте свойство с помощью @Column и определите тип как ArrayList, а не просто List. И заставить Person реализовать Serializable.

Но вы должны делать это, только если ваши мотивы очень ясны, потому что это правильное решение в некоторых очень редких случаях. Как отметил Паскаль, если вам когда-нибудь придется изменить Person, у вас будут головные боли.

0 голосов
/ 23 января 2010

Вы можете создать псевдосвойство (получатель и установщик), которое принимает / возвращает сериализованную форму, и аннотирует familyMembers с помощью @Transient. Это также должно было бы аннотировать геттеры, а не поля, для всех других свойств.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...