4
votes

Comment réutiliser la clause where dans EF

Je souhaite effectuer une requête à l'aide de EF et ma requête ressemble à la suivante

SELECT * FROM AspNetUsers U INNER JOIN UserPlan UP ON U.Id = UP.UserId 
WHERE UP.IsActive = 1
AND (
PlanId=2 OR (PlanId=3 AND EXISTS(SELECT 1 FROM [Group] WHERE AdminId=U.Id ))
)

Comment éviter d'interroger deux fois UserPlans? en SQL j'écrirais ce qui suit

var users = MyDbc.AspNetUsers.Where
            (
                  d => 
                  (
                      d.UserPlans.Where(m => m.IsActive == 1).FirstOrDefault().PlanId == 2
                      ||
                      (d.UserPlans.Where(m => m.IsActive == 1).FirstOrDefault().PlanId == 3 
                        && d.UserGroups.FirstOrDefault().Group.AdminId == d.Id)
                  )
            );


3 commentaires

Toute cette requête Linq sera traduite en une seule requête SQL, vous n'interrogez donc pas vraiment UserPlans deux fois.


Vous pouvez facilement vérifier la requête SQL résultante avec ((System.Data.Entity.Core.Objects.ObjectQuery) query) .ToTrace‌ String ()


J'ai utilisé le profileur pour vérifier la requête et il semble que j'ai deux instructions apply externes de UserPlans


3 Réponses :


4
votes

Utilisez simplement la syntaxe de requête intégrée:

var users = from user in MyDbc.AspNetUsers
            from plan in user.UserPlans.Where(m=>m.IsActive == 1)
            where plan.PlanId == 2 || plan.PlanId == 3 && ...

Elle est plus agile en termes de sélection des variables de temps de requête. Et il est BEAUCOUP plus lisible lorsque votre requête est volumineuse. Pour les requêtes simples, j'utilise toujours des extensions LINQ pures.

PS

Comme @juharr mentionné dans le commentaire, votre requête sera probablement être optimisé par le fournisseur SQL, donc vous êtes bon avec les performances, mais la lisibilité et la résistance aux pannes de votre requête sont en effet médiocres.


0 commentaires

1
votes

Je vais probablement emballer ceci dans une vue ou une procédure stockée (si vous avez besoin d'identifiants dynamiques) et charger cela séparément.

var users = MyDbc.Users.ToList();

puis l'appeler en c # ...

CREATE VIEW Users
AS   
SELECT * FROM AspNetUsers U INNER JOIN UserPlan UP ON U.Id = UP.UserId 
WHERE UP.IsActive = 1
AND (
PlanId=2 OR (PlanId=3 AND EXISTS(SELECT 1 FROM [Group] WHERE AdminId=U.Id ))
)
GO  

... comme ça.


0 commentaires

1
votes

Je pense que vous recherchez ceci. Vous pouvez simplement faire les deux vérifications directement dans le premier endroit.

d.UserPlans.Where(m => m.IsActive == 1 && 
(m.PlanId == 2 || (m.PlandId == 3 &&
d.UserGroups.FirstOrDefault().Group.AdminId == d.I)))


0 commentaires