在JPA(Hibernate)中,当我们自动生成ID字段时,假定用户不知道这个键。所以,在获取实体时,用户会根据ID以外的字段进行查询。在这种情况下我们如何获得实体(因为不能使用em.find()
)。JPA:如何根据ID以外的字段值获取实体?
我知道我们可以使用查询并稍后过滤结果。但是,有没有更直接的方法(因为据我了解,这是一个非常普遍的问题)。
在JPA(Hibernate)中,当我们自动生成ID字段时,假定用户不知道这个键。所以,在获取实体时,用户会根据ID以外的字段进行查询。在这种情况下我们如何获得实体(因为不能使用em.find()
)。JPA:如何根据ID以外的字段值获取实体?
我知道我们可以使用查询并稍后过滤结果。但是,有没有更直接的方法(因为据我了解,这是一个非常普遍的问题)。
看一看:
JPA query language
:The Java Persistence Query LanguageJPA Criteria API
:Using the Criteria API to Create Queries它并不像你说这是一个 “问题”。
Hibernate具有内置find()
,但您必须构建自己的查询才能获取特定对象。我建议使用Hibernate的的Criteria
:
Criteria criteria = session.createCriteria(YourClass.class);
YourObject yourObject = criteria.add(Restrictions.eq("yourField", yourFieldValue))
.uniqueResult();
这将创建你的当前类中的criteria
,将限制该列‘yourField’等于价值yourFieldValue
。 uniqueResult()
告诉它带来一个独特的结果。如果更多的对象匹配,你应该检索一个列表。
List<YourObject> list = criteria.add(Restrictions.eq("yourField", yourFieldValue)).list();
如果您还有其他问题,请随时提问。希望这可以帮助。
写这样一个自定义的方法如下
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;
}
我不敢相信这么简单的东西有多少代码。这是一个API失败国际海事组织。 – 2014-05-13 20:52:42
使用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();
}
如果您有实体Foo
的存储库并需要选择所有条目与确切的字符串值boo
(也适用于其他基元类型或实体类型)。要把它放到你的资料库界面:
List<Foo> findByBoo(String boo);
,如果您需要订购的结果:
List<Foo> findByBooOrderById(String boo);
多见于reference。
您可以添加对此答案的引用吗? – Jolley71717 2017-11-09 18:08:05
请注意,这只适用于Spring,而不是Hibernate或JPA。 – Scadge 2017-12-11 13:07:38
我已经写了一个库,可以帮助做到这一点。它只允许通过仅初始化要过滤的字段进行搜索:https://github.com/kg6zvp/GenericEntityEJB
基本上,您应该添加特定的唯一字段。我通常使用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;
}
}
我认为这里缺少一些东西:'criteria.select(root);''root'定义在哪里? – 2016-09-22 15:18:23
@JorgeCampos固定。谢谢。 – 2016-09-23 03:03:17
这很有帮助。谢谢。 – 2016-11-23 07:20:00
最佳做法是使用@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()
这是Hibernate的具体点吗?我可以在JPA中使用它吗? – Neo 2013-02-20 10:19:57
刚刚阅读,这也可以与JPA一起使用。 – Neo 2013-02-20 10:35:24
'Criteria'是Hibernate特有的,因为它来自'org.hibernate'包。 – 2013-02-20 12:14:29