如何使用 JPA 和 Hibernate 通过自定义对象实体属性进行查询
Posted
技术标签:
【中文标题】如何使用 JPA 和 Hibernate 通过自定义对象实体属性进行查询【英文标题】:How to query by custom object entity property with JPA and Hibernate 【发布时间】:2014-12-04 00:29:09 【问题描述】:编写一个 DAO 方法以通过电子邮件检索 appUsers,其中电子邮件属于 EmailAddress 类。一直在寻找如何做到这一点无济于事。有没有办法根据自定义对象的值来检索记录?当我有一个 String 或 int 类型的属性时,这似乎有效,但是如何获取与我的 EmailAddress 对象匹配的记录?
尝试了以下方法但不起作用:
public List<AppUser> findByEmail(EmailAddress email)
log.debug("finding " + getTable() + " instance by example");
AppUser appUser = new AppUser();
appUser.setEmail(email);
try
List<AppUser> results = this.sessionFactory.getCurrentSession()
.createCriteria(AppUser.class)
.add(Example.create(appUser)).list();
log.debug("find by example successful, result size: "
+ results.size());
return results;
catch (RuntimeException re)
log.error("find by example failed", re);
throw re;
这是我的 AppUser 类的相关部分
@Entity
@Table(name="AppUser")
public class AppUser extends BaseEntity
...
@Column(name="Email")
private EmailAddress email;
...
/**
* Gets this AppUser's associated email
*
* @return this AppUser's associated email
*/
public EmailAddress getEmail()
return this.email;
/**
* Sets this AppUser's associated email
*
* @param email this AppUser's associated email
*/
public void setEmail(EmailAddress email)
this.email = email;
这是我的 EmailAddress 类
public class EmailAddress implements Serializable
private static final long serialVersionUID = -6999956021169014445L;
private static final String AT_DELIMTER = "@";
private String emailAddress;
public EmailAddress()
public EmailAddress(String emailAddress)
setEmailAddress(emailAddress);
public String getEmailAddress()
return emailAddress;
public void setEmailAddress(String emailAddress) throws IllegalArgumentException
if (StringUtils.isEmpty(emailAddress))
throw new IllegalArgumentException("Parameter emailAddress cannot be blank.");
else if (!EmailValidator.getInstance(true).isValid(emailAddress))
throw new IllegalArgumentException("The email address " + emailAddress + " is not valid.");
this.emailAddress = emailAddress;
public String getUser()
return this.emailAddress.substring(0, this.emailAddress.indexOf(AT_DELIMTER));
public String getDomain()
return this.emailAddress.substring(this.emailAddress.indexOf(AT_DELIMTER) + 1);
public String toString()
return emailAddress;
@Override
public int hashCode()
final int prime = 31;
int result = 1;
result = prime * result
+ ((emailAddress == null) ? 0 : emailAddress.hashCode());
return result;
@Override
public boolean equals(Object obj)
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EmailAddress other = (EmailAddress) obj;
if (emailAddress == null)
if (other.emailAddress != null)
return false;
else if (!emailAddress.equals(other.emailAddress))
return false;
return true;
谢谢!
【问题讨论】:
【参考方案1】:将您的查询更改为:
List results = this.sessionFactory.getCurrentSession()
.createQuery("select au from AppUser au where au.email = :email")
.setParameter("email", email)
.list();
您需要实现 Hibernate custom UserType 以在加载时将 DB 字符串转换为 EmailAddress。
使用来自hibernate-types
项目的ImmutableType
作为自定义Hibernate Type
的基类,因为这样更容易实现。
【讨论】:
hmm...这里一定有其他事情发生,因为这仍然没有返回任何结果。这真的很奇怪,因为当我将属性字段作为字符串时,它可以工作,但是一旦我将其更改为 EmailAddress,它就不会返回任何结果。假设 Hibernate 可以进行这种翻译,我错了吗?【参考方案2】:将相关更改发布到 EmailAddress 类,以防其他人想看到它们:
public class EmailAddress implements UserType
...
@Override
public int[] sqlTypes()
return new int[] Types.NVARCHAR;
@Override
public Class<EmailAddress> returnedClass()
return EmailAddress.class;
@Override
public boolean equals(Object x, Object y) throws HibernateException
if (x == y)
return true;
if (y == null)
return false;
if (getClass() != y.getClass())
return false;
EmailAddress emailAddressX = (EmailAddress) x;
EmailAddress emailAddressY = (EmailAddress) y;
if (emailAddressX.getEmailAddress() == null)
if (emailAddressY.getEmailAddress() != null)
return false;
else if (!emailAddressX.getEmailAddress().equals(emailAddressY.getEmailAddress()))
return false;
return true;
@Override
public int hashCode(Object x) throws HibernateException
final int prime = 31;
int result = 1;
EmailAddress emailAddress = (EmailAddress) x;
result = prime * result
+ ((emailAddress == null) ? 0 : emailAddress.hashCode());
return result;
@Override
public Object nullSafeGet(ResultSet rs, String[] names,
SessionImplementor session, Object owner)
throws HibernateException, SQLException
EmailAddress emailAddress = null;
String value = rs.getString(names[0]);
if (!rs.wasNull())
emailAddress = new EmailAddress(value);
return emailAddress;
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index,
SessionImplementor session) throws HibernateException, SQLException
EmailAddress emailAddress = (EmailAddress) value;
st.setString(index, emailAddress.getEmailAddress());
@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) deepCopy(value);
@Override
public Object assemble(Serializable cached, Object owner)
throws HibernateException
return deepCopy(cached);
@Override
public Object replace(Object original, Object target, Object owner)
throws HibernateException
return deepCopy(original);
【讨论】:
以上是关于如何使用 JPA 和 Hibernate 通过自定义对象实体属性进行查询的主要内容,如果未能解决你的问题,请参考以下文章
如何通过使用 JPA + Hibernate 和 Spring-boot 在一个数据库中使用多个模式?
如何使用 Hibernate 和 JPA 处理填充下拉列表?
如何使用 JPA 和 Hibernate 删除带有 JOIN 的实体