Hier ist ein Beispiel für die Abfrage, die ich in 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 ist eine Viele-zu-Viele-Beziehung und es CompanyRolesToUsers
handelt sich um die Kreuzungstabelle.
Wir haben bereits den größten Teil unserer Site erstellt, und wir haben bereits den größten Teil der Filterung, indem wir Ausdrücke 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 etwas, das dies tut:
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 habe eine Frist. Ich konnte kein passendes Beispiel finden, aber ich bin mir sicher, dass es irgendwo da ist.
quelle
Für diese Anweisung, die besser geschrieben ist als, 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 respektable Wege sind, dies darzustellen. Ich bevorzuge in beiden Fällen die explizite "Join" -Syntax selbst, aber da ist sie ...
quelle
So 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 ebenfalls 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;
quelle
Sie könnten so etwas für Ihren Fall tun - (Syntax kann etwas abweichen). Schauen Sie sich auch diesen Link an
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;
quelle
Ok, hier ist eine grundlegende Join-Abfrage, die die richtigen Datensätze erhält:
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 Algorithmus integrieren lässt, den wir bereits installiert haben:
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 einem Poster im LINQtoSQL-Forum zu verdanken
quelle
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 außerdem, dass (2,3,4) eine Liste ist, die vom Benutzer der Web-App aus einer Kontrollkästchenliste ausgewählt wurde, und ich habe vergessen zu erwähnen, dass ich dies der Einfachheit halber nur fest codiert habe. Wirklich, es ist ein Array von CompanyRoleId-Werten, also kann es (1) oder (2,5) oder (1,2,3,4,6,7,99) sein.
Das andere, was ich klarer 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 um 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
quelle