2013-02-20 68 views
36

在JPA(Hibernate)中,当我们自动生成ID字段时,假定用户不知道这个键。所以,在获取实体时,用户会根据ID以外的字段进行查询。在这种情况下我们如何获得实体(因为不能使用em.find())。JPA:如何根据ID以外的字段值获取实体?

我知道我们可以使用查询并稍后过滤结果。但是,有没有更直接的方法(因为据我了解,这是一个非常普遍的问题)。

回答

24

它并不像你说这是一个 “问题”。

Hibernate具有内置find(),但您必须构建自己的查询才能获取特定对象。我建议使用Hibernate的Criteria

Criteria criteria = session.createCriteria(YourClass.class); 
YourObject yourObject = criteria.add(Restrictions.eq("yourField", yourFieldValue)) 
          .uniqueResult(); 

这将创建你的当前类中的criteria,将限制该列‘yourField’等于价值yourFieldValueuniqueResult()告诉它带来一个独特的结果。如果更多的对象匹配,你应该检索一个列表。

List<YourObject> list = criteria.add(Restrictions.eq("yourField", yourFieldValue)).list(); 

如果您还有其他问题,请随时提问。希望这可以帮助。

+0

这是Hibernate的具体点吗?我可以在JPA中使用它吗? – Neo 2013-02-20 10:19:57

+1

刚刚阅读,这也可以与JPA一起使用。 – Neo 2013-02-20 10:35:24

+0

'Criteria'是Hibernate特有的,因为它来自'org.hibernate'包。 – 2013-02-20 12:14:29

0

写这样一个自定义的方法如下

public Object findByYourField(Class entityClass, String yourFieldValue) 
{ 
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); 
    CriteriaQuery<Object> criteriaQuery = criteriaBuilder.createQuery(entityClass); 
    Root<Object> root = criteriaQuery.from(entityClass); 
    criteriaQuery.select(root); 

    ParameterExpression<String> params = criteriaBuilder.parameter(String.class); 
    criteriaQuery.where(criteriaBuilder.equal(root.get("yourField", params)); 

    TypedQuery<Object> query = entityManager.createQuery(criteriaQuery); 
    query.setParameter(params, yourFieldValue); 

    List<Object> queryResult = query.getResultList(); 

    Object returnObject = null; 

    if (CollectionUtils.isNotEmpty(queryResult)) 
    { 
     returnObject = queryList.get(0); 
    } 

    return returnObject; 
} 
+5

我不敢相信这么简单的东西有多少代码。这是一个API失败国际海事组织。 – 2014-05-13 20:52:42

-2

使用CrudRepository和JPA查询工作对我来说:

import org.springframework.data.jpa.repository.Query; 
import org.springframework.data.repository.CrudRepository; 
import org.springframework.data.repository.query.Param; 

public interface TokenCrudRepository extends CrudRepository<Token, Integer> { 

/** 
* Finds a token by using the user as a search criteria. 
* @param user 
* @return A token element matching with the given user. 
*/ 
    @Query("SELECT t FROM Token t WHERE LOWER(t.user) = LOWER(:user)") 
    public Token find(@Param("user") String user); 

} 

,并调用这样的查找自定义的方法:

public void destroyCurrentToken(String user){ 
    AbstractApplicationContext context = getContext(); 

    repository = context.getBean(TokenCrudRepository.class); 

    Token token = ((TokenCrudRepository) repository).find(user); 

    int idToken = token.getId(); 

    repository.delete(idToken); 

    context.close(); 
} 
6

如果您有实体Foo的存储库并需要选择所有条目与确切的字符串值boo(也适用于其他基元类型或实体类型)。要把它放到你的资料库界面:

List<Foo> findByBoo(String boo); 

,如果您需要订购的结果:

List<Foo> findByBooOrderById(String boo); 

多见于reference

+0

您可以添加对此答案的引用吗? – Jolley71717 2017-11-09 18:08:05

+0

请注意,这只适用于Spring,而不是Hibernate或JPA。 – Scadge 2017-12-11 13:07:38

4

基本上,您应该添加特定的唯一字段。我通常使用xxxUri字段。

class User { 

    @Id 
    // automatically generated 
    private Long id; 

    // globally unique id 
    @Column(name = "SCN", nullable = false, unique = true) 
    private String scn; 
} 

而你的商业方法会这样做。

public User findUserByScn(@NotNull final String scn) { 
    CriteriaBuilder builder = manager.getCriteriaBuilder(); 
    CriteriaQuery<User> criteria = builder.createQuery(User.class); 
    Root<User> from = criteria.from(User.class); 
    criteria.select(from); 
    criteria.where(builder.equal(from.get(User_.scn), scn)); 
    TypedQuery<User> typed = manager.createQuery(criteria); 
    try { 
     return typed.getSingleResult(); 
    } catch (final NoResultException nre) { 
     return null; 
    } 
} 
+0

我认为这里缺少一些东西:'criteria.select(root);''root'定义在哪里? – 2016-09-22 15:18:23

+1

@JorgeCampos固定。谢谢。 – 2016-09-23 03:03:17

+0

这很有帮助。谢谢。 – 2016-11-23 07:20:00

0

最佳做法是使用@NaturalId注释。在某些情况下它可以用作业务密钥,因为它太复杂了,所以有些字段被用作现实世界中的标识符。 例如,我有用户类作为主键的用户ID,并且电子邮件也是唯一的字段。所以我们可以使用电子邮件作为我们的天然ID

@Entity 
@Table(name="user") 
public class User { 
    @Id 
    @Column(name="id") 
    private int id; 

    @NaturalId 
    @Column(name="email") 
    private String email; 

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

,让我们的记录,只需简单地使用 'session.byNaturalId()'

Session session = sessionFactory.getCurrentSession(); 
User user = session.byNaturalId(User.class) 
        .using("email","[email protected]") 
        .load() 
相关问题