Отображение объекта аннотации в спящем режиме - PullRequest
1 голос
/ 10 ноября 2011

Я довольно новичок в hibernate, и я пытаюсь преобразовать свой проект JDBC в Hibernate.

Я использую аннотации, и мне удалось аннотировать основные вещи, однако яЯ застрял сейчас с более тяжелыми предметами, я не знаю, как их комментировать.Вот класс:

@Entity
@Table(name = "person")
public class Person {

    public Person{

    }

    // THIS WILL BE SOON INJECTED BY SPRING
    private static transient PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
    private static transient EmailValidator validator = EmailValidator.getInstance();

    @Id
    @Column(name = "person_id")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(name = "private_name", nullable = false, length = 20)
    private String privateName;

    @Column(name = "middle_name", length = 20)
    private String middleName;

    @Column(name = "family_name", nullable = false, length = 20)
    private String familyName;

    @Column(name = "age", nullable = false)
    private int age;

    @Column(name = "address1", nullable = false)
    private String address1;

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

    //How do I annotate this ? --> Google LIBPHONENUMBER

    private PhoneNumber phone;

    // How do I annotate this ? --> This is a normal PNG image file.
    private File image;

Редактировать: Файл ранее был отображен как BLOB.PhoneNumber ранее сохранялся как String и был преобразован с помощью конструктора PhoneNumber в Phonenumber.

Ответы [ 4 ]

4 голосов
/ 10 ноября 2011

Другие комментарии об использовании @Lob правильны для типа файла.Также верно, что если вы можете изменить схему, чтобы не сохранять данные файла в БД, вам, вероятно, следует сделать это.

Чтобы отобразить ваш класс PhoneNumber в поле базы данных, вам нужно будет использоватьпользовательский тип Hibernate.Он в основном говорит Hibernate, КАК сделать отображение объекта <-> db для классов, о которых он еще не знает.Настроить поле PhoneNumber в Person для использования пользовательского типа пользователя очень просто:

@Type(type = PhoneNumberType.CLASS_NAME)
@Column
private PhoneNumber phone;

Это предполагает очень простое хранение номера телефона в одну колонку.

Чтобы написать PhoneNumberType, вы 'Вам нужно будет реализовать UserType.С сборкой / дизассемблированием / deepCopy это выглядит ошеломляюще, но основная часть, которая вас волнует, это nullSetGet / Set, returnClass и sqlTypes.В итоге вы получите такой код внутри своего пользовательского типа:

@Override
public Class<?> returnedClass() {
    return PhoneNumber.class;
}

@Override
public int[] sqlTypes() {
    return new int[] { Types.VARCHAR };
}

@Override
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
    final String value = rs.getString(names[0]);
    return /* PhoneNumber instance created from string. */
}

@Override
public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
    if (value == null) {
        st.setNull(index, Types.VARBINARY);
        return;
    }

    st.setString(index, ((PhoneNumber) value).toString());
}

Вы можете найти много информации о том, как реализовать другие методы, через google, stackoverflow и hibernate javadocs.Это не так сложно сделать.

ОБНОВЛЕНИЕ: пользовательский тип с несколькими столбцами

Реализация CompositeUserType вместо просто UserType.Есть несколько изменений метода, которые вас волнуют.Сначала вы захотите определить несколько имен и типов свойств:

public String[] getPropertyNames() {
    return new String[] { "number", "code" };
}

public Type[] getPropertyTypes() {
    return new Type[] { StandardBasicTypes.STRING,
                        StandardBasicTypes.STRING };
}

Также необходимо реализовать getPropertyValue / setPropertyValue.Ваши реализации nullSafeXxxx изменится на чтение и запись двух свойств вместо одного:

@Override
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
    // Access column in order defined in getPropertyNames()
    final String number = rs.getString(names[0]);
    final String code = rs.getString(names[1]);
    return /* PhoneNumber instance created from number and country code. */
}
1 голос
/ 10 ноября 2011

Лично я бы сохранил только имя файла в объекте и сохранил файл в файловой системе, к которой принадлежат файлы.

В противном случае, сопоставьте его как BLOB-объект Hibernate (@Lob), и вы 'я бы хотел, чтобы это был байтовый массив (переводил бы на BLOB-объект).

IMO, как правило, создает больше проблем, чем стоит, но это частично зависит от БД, версии драйвера и т. д.

0 голосов
/ 23 октября 2015

Просто создайте Hibernate UserType для PhoneNumber

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

import org.apache.commons.lang.ObjectUtils;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.type.StringRepresentableType;
import org.hibernate.usertype.UserType;

import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
import com.tg.util.TGPhoneUtils;

public class PhoneNumberUserType implements UserType, StringRepresentableType<PhoneNumber>, Serializable {
    private static final long serialVersionUID = -364436436346432L;

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        return ObjectUtils.equals(x, y);
    }

    @Override
    public int hashCode(Object object) throws HibernateException {
        return object.hashCode();
    }

    @Override
    public Object deepCopy(Object value) throws HibernateException {
        return value;
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        return (Serializable) value;
    }

    @Override
    public Object assemble(Serializable cached, Object value) throws HibernateException {
        return cached;
    }

    @Override
    public Object replace(Object original, Object target, Object owner) throws HibernateException {
        return original;
    }

    @Override
    public String toString(PhoneNumber value) throws HibernateException {
        return value.toString();
    }

    @Override
    public Class<?> returnedClass() {
        return PhoneNumber.class;
    }

    @Override
    public int[] sqlTypes() {
        return new int[] { Types.VARCHAR };
    }

    @Override
    public PhoneNumber fromStringValue(String number) throws HibernateException {
        try {
            return PhoneNumberUtil.getInstance().parse(number, "US");
        } catch (NumberParseException e) {
            throw new HibernateException(e);
        }
    }

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor arg2, Object owner) throws HibernateException, SQLException {
        final String number = rs.getString(names[0]);
        if (number == null) {
            return null;
        }
        return TGPhoneUtils.parsePhoneNumber(number);
    }

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor si) throws HibernateException, SQLException {
        if (value == null) {
            st.setNull(index, Types.VARCHAR);
            return;
        }
        st.setString(index, TGPhoneUtils.formatPhoneNumber((PhoneNumber)value));
    }


}

и вот класс помощников

import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;

public class TGPhoneUtils {
    public static PhoneNumber parsePhoneNumber(String phoneNum) {
        if (phoneNum == null) {
            return null;
        }
        try {
            return PhoneNumberUtil.getInstance().parse(phoneNum, "US");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String formatPhoneNumber(PhoneNumber phoneNum) {
        if (phoneNum == null) {
            return null;
        }
        return PhoneNumberUtil.getInstance().format(phoneNum, PhoneNumberFormat.E164);
    }
}
0 голосов
/ 10 ноября 2011

Вы можете комментировать PhoneNumber следующим образом:

@ManyToOne
@JoinColumn(name = "PHONE_NUMBER")
private PhoneNumber phone;

Предполагается, что столбец PHONE_NUMBER существует и сопоставляется с идентификатором номера телефона. Класс PhoneNumber также необходимо аннотировать. Это предполагает, что вы, возможно, захотите разделить телефонный номер между различными объектами (многие к одному).

Что касается файла, вам, вероятно, необходимо решить, хотите ли вы на самом деле сохранить данные файла в БД (обычно это не очень хорошая идея). В противном случае вы можете просто сохранить строку с путем к файлу.

...