webentwicklung-frage-antwort-db.com.de

Wie mache ich eine Unterabfrage in LINQ?

Hier ist ein Beispiel für die Abfrage, die ich nach LINQ konvertieren möchte:

SELECT *
FROM Users
WHERE Users.lastname LIKE '%fra%'
    AND Users.Id IN (
         SELECT UserId 
         FROM CompanyRolesToUsers 
         WHERE CompanyRoleId in (2,3,4) )

Es gibt eine FK-Beziehung zwischen CompanyRolesToUsers und Users, aber es gibt viele zu viele Beziehungen und CompanyRolesToUsers ist die Junction-Tabelle.

Wir haben bereits einen Großteil unserer Website erstellt und die Filterung funktioniert größtenteils, indem wir Expressions mit einer PredicateExtensions-Klasse erstellen.

Der Code für die einfachen Filter sieht ungefähr so ​​aus:

 if (!string.IsNullOrEmpty(TextBoxLastName.Text))
 {
     predicateAnd = predicateAnd.And(c => c.LastName.Contains(
                                     TextBoxLastName.Text.Trim()));
 }

e.Result = context.Users.Where(predicateAnd);

Ich versuche, ein Prädikat für eine Unterauswahl in einer anderen Tabelle hinzuzufügen. (CompanyRolesToUsers)

Was ich hinzufügen möchte, ist Folgendes:

int[] selectedRoles = GetSelectedRoles();
if( selectedRoles.Length > 0 )
{
    //somehow only select the userid from here ???:
    var subquery = from u in CompanyRolesToUsers
                   where u.RoleID in selectedRoles
                   select u.UserId;

    //somehow transform this into an Expression ???:
    var subExpression = Expression.Invoke(subquery);

    //and add it on to the existing expressions ???:
    predicateAnd = predicateAnd.And(subExpression);
}

Gibt es eine Möglichkeit, dies zu tun? Es ist frustrierend, weil ich die gespeicherte Prozedur leicht schreiben kann, aber ich bin neu in dieser LINQ-Sache und ich habe eine Frist. Ich habe kein passendes Beispiel gefunden, aber ich bin mir sicher, dass es irgendwo da ist.

65
marcel_g

Für diese Anweisung ist keine Unterabfrage erforderlich

select u.* 
from Users u, CompanyRolesToUsers c
where u.Id = c.UserId        --join just specified here, perfectly fine
and u.lastname like '%fra%'
and c.CompanyRoleId in (2,3,4)

oder

select u.* 
from Users u inner join CompanyRolesToUsers c
             on u.Id = c.UserId    --explicit "join" statement, no diff from above, just preference
where u.lastname like '%fra%'
  and c.CompanyRoleId in (2,3,4)

Davon abgesehen wäre es in LINQ

from u in Users
from c in CompanyRolesToUsers 
where u.Id == c.UserId &&
      u.LastName.Contains("fra") &&
      selectedRoles.Contains(c.CompanyRoleId)
select u

oder

from u in Users
join c in CompanyRolesToUsers 
       on u.Id equals c.UserId
where u.LastName.Contains("fra") &&
      selectedRoles.Contains(c.CompanyRoleId)
select u

Was wiederum beide respektable Möglichkeiten sind, dies darzustellen. Ich bevorzuge die explizite "Join" -Syntax in beiden Fällen selbst, aber da ist es ...

22
TheSoftwareJedi

Auf diese Weise habe ich Unterabfragen in LINQ durchgeführt. Ich denke, dies sollte das bekommen, was Sie wollen. Sie können die explizite CompanyRoleId == 2 ... durch eine andere Unterabfrage für die verschiedenen gewünschten Rollen ersetzen oder auch beitreten.

from u in Users
join c in (
    from crt in CompanyRolesToUsers
    where CompanyRoleId == 2
    || CompanyRoleId == 3
    || CompanyRoleId == 4) on u.UserId equals c.UserId
where u.lastname.Contains("fra")
select u;
5
Noah

Ok, hier ist eine grundlegende Join-Abfrage, die die richtigen Datensätze abruft:

   int[] selectedRolesArr = GetSelectedRoles();
    if( selectedRolesArr != null && selectedRolesArr.Length > 0 ) 
    {

    //this join version requires the use of distinct to prevent muliple records
        //being returned for users with more than one company role.
    IQueryable retVal = (from u in context.Users
                        join c in context.CompanyRolesToUsers
                          on u.Id equals c.UserId
                        where u.LastName.Contains( "fra" ) &&
                            selectedRolesArr.Contains( c.CompanyRoleId )
                        select  u).Distinct();
}

Aber hier ist der Code, der sich am einfachsten in den bereits vorhandenen Algorithmus integrieren lässt:

int[] selectedRolesArr = GetSelectedRoles(); 
if ( useAnd ) 
       { 
          predicateAnd = predicateAnd.And( u => (from c in context.CompanyRolesToUsers 
                       where selectedRolesArr.Contains(c.CompanyRoleId) 
                       select c.UserId).Contains(u.Id)); 
        } 
        else 
        { 
           predicateOr = predicateOr.Or( u => (from c in context.CompanyRolesToUsers 
                          where selectedRolesArr.Contains(c.CompanyRoleId) 
                         select c.UserId).Contains(u.Id) ); 
        } 

das ist dank eines Posters im LINQtoSQL-Forum

2
marcel_g

Sie könnten so etwas für Ihren Fall tun Syntax ist möglicherweise etwas abweichend). Schauen Sie sich auch diese an --- (Link

subQuery = (from crtu in CompanyRolesToUsers where crtu.RoleId==2 || crtu.RoleId==3 select crtu.UserId).ToArrayList();

finalQuery = from u in Users where u.LastName.Contains('fra')  && subQuery.Contains(u.Id) select u;
2
Perpetualcoder

Hier ist eine Version von SQL, die die richtigen Datensätze zurückgibt:

select distinct u.* 
from Users u, CompanyRolesToUsers c
where u.Id = c.UserId        --join just specified here, perfectly fine
and u.firstname like '%amy%'
and c.CompanyRoleId in (2,3,4)

Beachten Sie auch, dass (2,3,4) eine Liste ist, die vom Web-App-Benutzer aus einer Checkbox-Liste ausgewählt wurde, und ich habe vergessen zu erwähnen, dass ich dies der Einfachheit halber nur fest codiert habe. In Wirklichkeit handelt es sich um ein Array von CompanyRoleId-Werten, also kann es sich um (1) oder (2,5) oder (1,2,3,4,6,7,99) handeln.

Das andere, was ich genauer spezifizieren sollte, ist, dass die PredicateExtensions verwendet werden, um Prädikatklauseln dynamisch zum Where für die Abfrage hinzuzufügen, abhängig davon, welche Formularfelder der Web-App-Benutzer ausgefüllt hat. Der schwierige Teil für mich ist also, wie die Arbeitsabfrage in einen LINQ-Ausdruck umzuwandeln, den ich an die dynamische Liste der Ausdrücke anhängen kann.

Ich werde einige der Beispiel-LINQ-Abfragen ausprobieren und prüfen, ob ich sie in unseren Code integrieren kann, und dann meine Ergebnisse veröffentlichen. Vielen Dank!

marcel

1
marcel_g