2010-04-29 15 views

Répondre

7

Je suppose que vous utilisez une version d'Hibernate 2.0 qui implémente JPA. Voici une solution JPA 2.0 qui devrait fonctionner avec n'importe quelle implémentation conforme.

Veuillez annoter uuids avec l'annotation @ElementCollection de JPA. N'utilisez pas @CollectionOfElements d'Hibernate comme mentionné dans d'autres commentaires de réponse. Ce dernier a une fonctionnalité équivalente mais est being deprecated.

Foobar.java se penchera à peu près comme ceci:

@Entity 
public class Foobar implements Serializable { 

    // You might have some other id 
    @Id 
    private Long id; 

    @ElementCollection 
    private List<String> uuids; 

    // Getters/Setters, serialVersionUID, ... 

} 

Voilà comment vous pouvez construire un CriteriaQuery pour sélectionner tous les Foobar s dont uuids contiennent "abc123".

public void getFoobars() { 
{ 
    EntityManager em = ... // EM by injection, EntityManagerFactory, whatever 

    CriteriaBuilder b = em.getCriteriaBuilder(); 
    CriteriaQuery<Foobar> cq = b.createQuery(Foobar.class); 
    Root<Foobar> foobar = cq.from(Foobar.class); 

    TypedQuery<Foobar> q = em.createQuery(
      cq.select(foobar) 
       .where(b.isMember("abc123", foobar.<List<String>>get("uuids")))); 

    for (Foobar f : q.getResultList()) { 
     // Do stuff with f, which will have "abc123" in uuids 
    } 
} 

J'ai fait un programme de preuve de concept autonome en jouant avec cela. Je ne peux pas l'exclure maintenant. Veuillez commenter si vous voulez que le POC soit poussé vers github.

+0

Essayé avec hibernate 3.6.7-Final et ne fonctionne pas (il semble être un bug en hibernation). – greuze

-2

Pour commencer, je ne pense pas que Hibernate puisse mapper un List<String>. Cependant, il peut mapper une liste d'autres entités.

Donc, si votre code était quelque chose comme ceci:

@Entity 
public class Foobar { 

    private List<EntityObject> uuids; 
    ... 
} 

Et le EntityObject a un String -property appelé str, les critères pourraient ressembler à ceci:

List<Foobar> returns = (List<Foobar>) session 
       .createCriteria.(Foobar.class, "foobars") 
       .createAlias("foobars.uuids", "uuids") 
        .add(Restrictions.like("uuids.str", "%abc123%")) 
       .list(); 
+1

Il n'y a aucun problème à utiliser une liste de chaînes, il suffit de l'annoter avec @CollectionOfElements. Votre solution m'oblige à créer une classe d'entité supplémentaire, ce que j'espérais éviter avec cette question très spécifique. –

1

Vous pouvez utiliser une requête comme dans l'exemple ci-dessous ou vous pouvez convertir cela en NamedQuery. Malheureusement, il ne semble pas y avoir un moyen de le faire avec des critères.

List<Foobar> result = session 
    .createQuery("from Foobar f join f.uuids u where u =: mytest") 
    .setString("mytest", "acb123") 
    .list(); 
1

Ce que vous demandez n'est pas pris en charge par hibernate. Voir http://opensource.atlassian.com/projects/hibernate/browse/HHH-869

Voici une solution de contournement disponible dans le billet d'JIRA:

entityCriteria.add(Restrictions.sqlRestriction(
    "fooAlias.id in (select e.id from foobar_table e, values_table v" + 
    " where e.id = v.entity_id and v.field = ?)", "abc123"), Hibernate.String)) ; 
2

J'ai trouvé ce message il y a un an, et j'ai fait cette méthode, si cela peut aider quelqu'un avec le même problème que j'avais il y a quelques heures.

Public List<EntityObject> getHasString(String string) { 
     return getSession().createCriteria(EntityObject.class) 
           .add(Restriction.like("property-name", string, MatchMode.ANYWHERE).ignoreCase(); 
          .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY) 
          .list(); 

Fait de même avec un groupe de chaînes aussi.

public List<EntityObject> getByStringList(String[] tab) { 
     Criterion c = Restrictions.like("property-name", tab[tab.length-1], MatchMode.ANYWHERE).ignoreCase(); 
     if(tab.length > 1) { 
      for(int i=tab.length-2; i >= 0 ; i--) { 
       c = Restrictions.or(Restrictions.like("property-name",tab[i], MatchMode.ANYWHERE).ignoreCase(), c); 
      } 
     } 
     return getSession().createCriteria(EntityObject.class) 
           .add(c) 
          .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY) 
          .list(); 
    } 

Il fonctionne avec les instructions "or", mais peut facilement être remplacé par des instructions "and".

0

La solution avec le sqlRestriction de jira http://opensource.atlassian.com/projects/hibernate/browse/HHH-869 a semblé la meilleure manière d'aller pour moi puisque j'utilise fortement des critères api. Je devais modifier le code de Thierry il a travaillé dans mon cas

Modèle:

@Entity 
public class PlatformData 
{ 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long iID; 

    private List<String> iPlatformAbilities = new ArrayList<String>(); 
} 

appel Critères:

tCriteria.add(Restrictions.sqlRestriction(
     "{alias}.id in (select e.id from platformData e, platformdata_platformabilities v" 
      + " where e.id = v.platformdata_id and v.element = ?)", aPlatformAbility.toString(), 
     Hibernate.STRING)); 
3

Je sais que c'est vieille question, mais je viens de rencontrer ce problème et solution trouvée.

Si vous souhaitez utiliser les critères de mise en veille prolongée, vous pouvez rejoindre votre collection uuids et utiliser sa propriété elements pour faire correspondre les éléments. Juste comme ça:

session.createCriteria(Foobar.class) 
    .createAlias("uuids", "uuids") 
    .add(Restrictions.eq("uuids.elements", "MyUUID")) 
    .list() 
+1

Vous pouvez également utiliser à la place de "elements" la constante 'CollectionPropertyNames.COLLECTION_ELEMENTS'. –