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.
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 ...
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;
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
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;
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