2013-02-20 67 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() 
相關問題