2 votes

Comment exprimer une requête contenant une sous-requête WHERE..IN en utilisant l'API QueryOver de NHibernate ?

J'ai un modèle d'objet où un Order contient de nombreux LineItems et chaque LineItem est associé à un Product . Dans le modèle objet, il s'agit d'associations à sens unique -- une LineItem ne sait rien de son Order .

Class diagram

Je veux rechercher les commandes qui contiennent un poste avec un nom de produit correspondant à une chaîne de caractères, en retournant une ligne pour chaque commande (de sorte que la pagination puisse être effectuée).

SELECT * FROM Orders 
WHERE OrderID IN (
    SELECT DISTINCT OrderID 
    FROM LineItems 
    INNER JOIN Products on LineItems.ProductID = Products.ProductID
    WHERE Products.Name = 'foo'
)

Étant donné que j'ai un ICriteria ou un IQueryOver représentant la sous-requête, comment puis-je l'appliquer à ma requête de commande racine ?

var subquery = QueryOver.Of<LineItem>
                        .Where(l => l.Product.Name == "foo")
                        .TransformUsing(Transformers.DistinctRootEntity);

J'ai trouvé de nombreux exemples qui partent du principe que l'objet Root de la requête se trouve du côté "many" d'une relation one-to-many, mais je n'arrive pas à trouver comment ajouter une restriction sur quelque chose que l'objet Root a beaucoup de .

3voto

dotjoe Points 11959

Je ferais en sorte que la relation entre la commande et le poste soit bidirectionnelle pour permettre des requêtes efficaces (réduire le nombre de jointures nécessaires). Mais si, pour une raison étrange, vous ne pouvez pas le faire, vous devrez lancer la sous-requête à partir de la commande...

LineItem lineItemAlias = null;
Product productAlias = null;

var subQuery = QueryOver.Of<Order>()
            .JoinAlias(x => x.LineItems, () => lineItemAlias)
            .JoinAlias(() => lineItemAlias.Product, () => productAlias)
            .Where(() => productAlias.Name == "foo")
            .Select(Projections.Group<Order>(x => x.Id));

var results = Session.QueryOver<Order>()
              .WithSubquery.WhereProperty(x => x.Id).In(subQuery)
              .List();

2voto

frictionlesspulley Points 3416

La traduction directe du SQL que vous avez fourni peut être réalisée en utilisant ceci

var subQuery = 
      QueryOver.Of<LineItem>(() => lineItem)
            .JoinAlias(() => lineItem.Products, () => product)
            .Where(() => product.Name == "foo")
            .Select(Projections.Distinct(
                      Projections.Property(()=> lineItem.Order.Id)));;

var theQueryYouNeed =  
               QueryOver.Of<Orders>(() => order)
              .WithSubquery.WherePropertyIn(() => order.Id).In(subQuery); 

Toutefois, si votre LineItem L'entité n'a pas de Order Propriété alors vous ne pouvez pas vraiment utiliser la sous-requête.

Si vous avez besoin de trouver

Toutes les commandes qui ont un LineItem dont le nom de produit est "foo" alors

var theQueryYouNeed = 
  QueryOver.Of<Orders>(() => order)
     .JoinAlias(() => order.LineItems, () => lineItem)
     .JoinAlias(() => lineItem.Product, () => product)
     .Where(() => product.Name == "foo")
     .TransformUsing(new DistinctRootEntityResultTransformer())

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X