web-dev-qa-db-fra.com

JPA: Comment obtenir une entité basée sur une valeur de champ autre qu'un identifiant?

Dans JPA (Hibernate), lorsque nous générons automatiquement le champ ID, on suppose que l'utilisateur n'a aucune connaissance de cette clé. Ainsi, lorsqu’il obtient l’entité, l’utilisateur interroge sur un champ autre que l’ID. Comment pouvons-nous obtenir l'entité dans ce cas (puisque em.find() ne peut pas être utilisé). 

Je comprends que nous pouvons utiliser une requête et filtrer les résultats plus tard. Mais existe-t-il un moyen plus direct (car c’est un problème très courant, si je comprends bien).

43
Neo

Ce n'est pas un "problème" comme vous l'avez dit.

Hibernate a la find() intégrée, mais vous devez créer votre propre requête pour obtenir un objet particulier. Je recommande d’utiliser Hibernate 's Criteria:

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

Cela créera une criteria sur votre classe actuelle, en ajoutant la restriction que la colonne "yourField" est égale à la valeur yourFieldValue. uniqueResult() lui dit d'apporter un résultat unique. Si plusieurs objets correspondent, vous devriez récupérer une liste.

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

Si vous avez d'autres questions, n'hésitez pas à demander. J'espère que cela t'aides.

30
Raul Rene

si vous avez un référentiel pour entité Foo et devez sélectionner toutes les entrées avec la valeur de chaîne exacte boo (fonctionne également pour d'autres types primitifs ou types d'entité). Mettez ceci dans votre interface de référentiel:

List<Foo> findByBoo(String boo);

si vous avez besoin de commander des résultats:

List<Foo> findByBooOrderById(String boo);

Voir plus à référence .

12
cici

Fondamentalement, vous devez ajouter un champ unique spécifique. J'utilise habituellement des champs xxxUri.

class User {

    @Id
    // automatically generated
    private Long id;

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

Et votre méthode commerciale fera comme ça.

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;
    }
}
7
Jin Kwon

La meilleure pratique consiste à utiliser l'annotation @NaturalId. Elle peut être utilisée comme clé commerciale dans certains cas. Elle est trop compliquée. Certains champs utilisent donc cet identifiant dans le monde réel. Par exemple, j'ai une classe d'utilisateurs avec l'ID utilisateur comme clé primaire et le courrier électronique est également un champ unique. Nous pouvons donc utiliser le courrier électronique comme identifiant naturel 

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

Pour obtenir notre enregistrement, utilisez simplement 'session.byNaturalId ()'

Session session = sessionFactory.getCurrentSession();
User user = session.byNaturalId(User.class)
                   .using("email","[email protected]")
                   .load()
2
Chenhai-胡晨海

Ecrivez une méthode personnalisée comme ceci: 

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 = queryResult.get(0);
    }

    return returnObject;
}
2
tinker_fairy

J'ai écrit une bibliothèque qui aide précisément à faire cela. Il permet une recherche par objet simplement en initialisant les champs que vous souhaitez filtrer par: https://github.com/kg6zvp/GenericEntityEJB

0
KG6ZVP

Jettes un coup d'oeil à:

0
Wilhelm Kleu

Dans mon application de démarrage Spring, j'ai résolu un problème similaire à celui-ci:

@Autowired
private EntityManager entityManager;

public User findByEmail(String email) {
    User user = null;
    Query query = entityManager.createQuery("SELECT u FROM User u WHERE u.email=:email");
    query.setParameter("email", email);
    try {
        user = (User) query.getSingleResult();
    } catch (Exception e) {
        // Handle exception
    }
    return user;
}
0
Sareneathenodny