Hibernate注释对象映射

时间:2011-11-10 18:00:36

标签: java hibernate annotations dao

我对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 个答案:

答案 0 :(得分:4)

关于使用@Lob的其他注释对于文件类型是正确的。如果您可以更改架构以不在DB中保存文件数据,那也是正确的。那么您可能应该这样做。

要将PhoneNumber类映射到数据库字段,您将需要使用Hibernate自定义UserType。它基本上告诉Hibernate如何为它不知道的类做对象< - > db映射。在Person中告诉PhoneNumber字段以使用自定义用户类型很容易:

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

这假设电话号码的单列存储非常简单。

要编写PhoneNumberType,您需要实现UserType。使用汇编/反汇编/ deepCopy看起来势不可挡,但您关心的主要部分是nullSetGet / Set,returnedClass和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 :(得分:1)

就个人而言,我只在对象中存储文件名,并将文件保存在文件所在的文件系统中。

否则,将其映射为Hibernate blob(@Lob)并且您希望它是一个字节数组(将转换为blob)。

IMO通常会产生比它更值得的麻烦,但这部分取决于数据库,驱动程序修订等。

答案 2 :(得分:0)

您可以像这样注释PhoneNumber:

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

假设PHONE_NUMBER列存在并映射到电话号码的ID。 PhoneNumber类也需要注释。这假设您希望在不同实体之间共享电话号码(多对一)。

关于文件,您可能需要决定是否要将文件数据实际存储在db中(通常不是一个好主意)。否则,你可以只存储一个带有文件路径的字符串。

答案 3 :(得分:0)

只需为PhoneNumber创建一个Hibernate UserType

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);
    }
}