Was ist die Verwendung von IQueryable
im Zusammenhang mit LINQ?Verwenden von IQueryable mit Linq
Wird es für die Entwicklung von Erweiterungsmethoden oder für andere Zwecke verwendet?
Was ist die Verwendung von IQueryable
im Zusammenhang mit LINQ?Verwenden von IQueryable mit Linq
Wird es für die Entwicklung von Erweiterungsmethoden oder für andere Zwecke verwendet?
Marc Gravell's answer ist sehr komplett, aber ich dachte, dass ich etwas über diesen aus Anwendersicht hinzufügen würde, wie gut ...
Der Hauptunterschied, aus der Sicht des Benutzers, ist, dass, Wenn Sie IQueryable<T>
verwenden (mit einem Anbieter, der Dinge richtig unterstützt), können Sie eine Menge Ressourcen speichern. Wenn Sie z. B. mit einer entfernten Datenbank arbeiten und viele ORM-Systeme verwenden, haben Sie die Möglichkeit, Daten aus einer Tabelle auf zwei Arten abzurufen: Eine, die IEnumerable<T>
zurückgibt, und eine, die eine IQueryable<T>
zurückgibt. Angenommen, Sie haben eine Produkttabelle und möchten alle Produkte mit Kosten von> 25 € abrufen.
Wenn Sie das tun:
IEnumerable<Product> products = myORM.GetProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);
Was hier passiert, ist die Datenbank lädt alle der Produkte und übergibt sie an das Programm über den Draht. Ihr Programm filtert dann die Daten. Im Wesentlichen führt die Datenbank eine SELECT * FROM Products
aus und gibt JEDES Produkt an Sie zurück.
Mit den richtigen IQueryable<T>
Anbietern, auf der anderen Seite, können Sie tun:
IQueryable<Product> products = myORM.GetQueryableProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);
Der Code sieht gleich aus, aber der Unterschied ist, dass der ausgeführten SQL SELECT * FROM Products WHERE Cost >= 25
sein wird.
Von Ihrem POV als Entwickler sieht das gleich aus. Doch aus anwendungstechnischer Sicht können Sie nur zurückgeben 2 Datensätze über das Netzwerk statt 20.000 ....
Im Wesentlichen seiner Arbeit zu IEnumerable<T>
sehr ähnlich ist - eine abfragbaren Datenquelle darstellen - das ist Unterschied, dass die verschiedenen LINQ-Methoden (auf Queryable
) spezifischer sein können, die Abfrage mit Expression
Bäumen zu bauen, anstatt Delegierten (die ist was Enumerable
verwendet).
Die Ausdrucksbäume können von Ihrem ausgewählten LINQ-Anbieter überprüft und in eine tatsächliche Abfrage umgewandelt werden - obwohl das eine schwarze Kunst an sich ist.
Das ist wirklich auf die ElementType
, Expression
und Provider
- aber in Wirklichkeit Sie selten Notwendigkeit darüber, wie ein Benutzer zu kümmern. Nur ein LINQ Implementierer muss die blutigen Details kennen.
Re Kommentare; Ich bin nicht ganz sicher, was Sie als Beispiel wollen, aber betrachten Sie LINQ-to-SQL; Das zentrale Objekt ist hier eine DataContext
, die unseren Datenbank-Wrapper darstellt. Dies hat normalerweise eine Eigenschaft pro Tabelle (z. B. Customers
) und eine Tabelle implementiert IQueryable<Customer>
. Aber wir verwenden nicht so viel direkt; berücksichtigen:
using(var ctx = new MyDataContext()) {
var qry = from cust in ctx.Customers
where cust.Region == "North"
select new { cust.Id, cust.Name };
foreach(var row in qry) {
Console.WriteLine("{0}: {1}", row.Id, row.Name);
}
}
Diese wird (durch die C# Compiler):
var qry = ctx.Customers.Where(cust => cust.Region == "North")
.Select(cust => new { cust.Id, cust.Name });
die wiederum (durch den C# Compiler) interpretiert wird als:
var qry = Queryable.Select(
Queryable.Where(
ctx.Customers,
cust => cust.Region == "North"),
cust => new { cust.Id, cust.Name });
Wichtig ist, auf den statischen Methoden Queryable
nehmen Ausdrucksbäume, die - anstatt regulärer IL, zu einem Objektmodell kompiliert werden. Zum Beispiel - nur an der „Wo?“ Sucht, gibt uns etwas vergleichbar:
var cust = Expression.Parameter(typeof(Customer), "cust");
var lambda = Expression.Lambda<Func<Customer,bool>>(
Expression.Equal(
Expression.Property(cust, "Region"),
Expression.Constant("North")
), cust);
... Queryable.Where(ctx.Customers, lambda) ...
hat noch keinen Compiler für uns viel zu tun? Dieses Objektmodell kann auseinandergerissen werden, kontrolliert, was es bedeutet, und durch den TSQL Generator wieder zusammen setzen - was so etwas wie:
SELECT c.Id, c.Name
FROM [dbo].[Customer] c
WHERE c.Region = 'North'
(der String kann bis als Parameter am Ende, ich kann mich nicht erinnern,)
Nichts davon wäre möglich, wenn wir gerade einen Delegierten verwendet hätten. Und dieser ist der Punkt von Queryable
/IQueryable<T>
: es bietet den Einstiegspunkt für die Verwendung von Ausdrucksbäumen.
All dies ist sehr komplex, also ist es ein guter Job, dass der Compiler es für uns einfach und leicht macht. Weitere Informationen finden Sie unter "C# in Depth" oder "LINQ in Action", die beide diese Themen abdecken.
Wenn es Ihnen nichts ausmacht können Sie mich mit einfach verständlichen Beispiel aktualisieren (wenn Sie Zeit haben). – user190560
Können Sie erklären "Wo ist die Definition von" GetQueryableProducts(); "?" in Herr Reed Copsey antworten – Pankaj
Genossen die Linie der Übersetzung von Ausdrücken zu einer Abfrage ist "schwarze Kunst an sich" ... eine Menge Wahrheit zu diesem – afreeland
Es ermöglicht weitere Abfragen weiter unten auf der Linie.Wenn dies jenseits einer Dienstgrenze war, würde dem Benutzer dieses IQueryable-Objekts erlaubt werden, mehr damit zu tun.
Zum Beispiel, wenn Sie Lazy Loading mit Nhibernate verwenden, kann dies dazu führen, dass das Diagramm bei Bedarf geladen wird.
Obwohl Reed Copsey und Marc Gravell bereits über IQueryable(and also IEnumerable)
genug beschrieben, obwohl ich wenig mehr hier hinzufügen möchten, indem Sie eine small example on IQueryable and IEnumerable
Bereitstellung als viele Nutzer gefragt davon
Beispiel: I zwei Tabelle in der Datenbank erstellt haben
CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Gender] [nchar](1) NOT NULL)
CREATE TABLE [dbo].[Person]([PersonId] [int] NOT NULL PRIMARY KEY,[FirstName] [nvarchar](50) NOT NULL,[LastName] [nvarchar](50) NOT NULL)
Primary key(PersonId)
der Tabelle Employee
ist auch forgein key(personid)
der Tabelle Person
Next i hinzugefügt ado.net Entitätsmodell in meiner Anwendung und erstellen unter Serviceklasse auf diesem
public class SomeServiceClass
{
public IQueryable<Employee> GetEmployeeAndPersonDetailIQueryable(IEnumerable<int> employeesToCollect)
{
DemoIQueryableEntities db = new DemoIQueryableEntities();
var allDetails = from Employee e in db.Employees
join Person p in db.People on e.PersonId equals p.PersonId
where employeesToCollect.Contains(e.PersonId)
select e;
return allDetails;
}
public IEnumerable<Employee> GetEmployeeAndPersonDetailIEnumerable(IEnumerable<int> employeesToCollect)
{
DemoIQueryableEntities db = new DemoIQueryableEntities();
var allDetails = from Employee e in db.Employees
join Person p in db.People on e.PersonId equals p.PersonId
where employeesToCollect.Contains(e.PersonId)
select e;
return allDetails;
}
}
sie gleiche Linq enthält.Er rief in program.cs
wie unten
class Program
{
static void Main(string[] args)
{
SomeServiceClass s= new SomeServiceClass();
var employeesToCollect= new []{0,1,2,3};
//IQueryable execution part
var IQueryableList = s.GetEmployeeAndPersonDetailIQueryable(employeesToCollect).Where(i => i.Gender=="M");
foreach (var emp in IQueryableList)
{
System.Console.WriteLine("ID:{0}, EName:{1},Gender:{2}", emp.PersonId, emp.Person.FirstName, emp.Gender);
}
System.Console.WriteLine("IQueryable contain {0} row in result set", IQueryableList.Count());
//IEnumerable execution part
var IEnumerableList = s.GetEmployeeAndPersonDetailIEnumerable(employeesToCollect).Where(i => i.Gender == "M");
foreach (var emp in IEnumerableList)
{
System.Console.WriteLine("ID:{0}, EName:{1},Gender:{2}", emp.PersonId, emp.Person.FirstName, emp.Gender);
}
System.Console.WriteLine("IEnumerable contain {0} row in result set", IEnumerableList.Count());
Console.ReadKey();
}
}
Die output is same for both
offensichtlich definiert
ID:1, EName:Ken,Gender:M
ID:3, EName:Roberto,Gender:M
IQueryable contain 2 row in result set
ID:1, EName:Ken,Gender:M
ID:3, EName:Roberto,Gender:M
IEnumerable contain 2 row in result set
Die Frage ist also, was/wo ist der Unterschied? Es scheint nicht irgendeinen Unterschied richtig zu haben? Ja wirklich!!
Lassen Sie uns einen Blick auf SQL-Abfragen generiert und ausgeführt von Unternehmen framwork 5 während dieser Periode
IQueryable execution part
--IQueryableQuery1
SELECT
[Extent1].[PersonId] AS [PersonId],
[Extent1].[Gender] AS [Gender]
FROM [dbo].[Employee] AS [Extent1]
WHERE ([Extent1].[PersonId] IN (0,1,2,3)) AND (N'M' = [Extent1].[Gender])
--IQueryableQuery2
SELECT
[GroupBy1].[A1] AS [C1]
FROM (SELECT
COUNT(1) AS [A1]
FROM [dbo].[Employee] AS [Extent1]
WHERE ([Extent1].[PersonId] IN (0,1,2,3)) AND (N'M' = [Extent1].[Gender])
) AS [GroupBy1]
IEnumerable execution part
--IEnumerableQuery1
SELECT
[Extent1].[PersonId] AS [PersonId],
[Extent1].[Gender] AS [Gender]
FROM [dbo].[Employee] AS [Extent1]
WHERE [Extent1].[PersonId] IN (0,1,2,3)
--IEnumerableQuery2
SELECT
[Extent1].[PersonId] AS [PersonId],
[Extent1].[Gender] AS [Gender]
FROM [dbo].[Employee] AS [Extent1]
WHERE [Extent1].[PersonId] IN (0,1,2,3)
Common script for both execution part
/* these two query will execute for both IQueryable or IEnumerable to get details from Person table
Ignore these two queries here because it has nothing to do with IQueryable vs IEnumerable
--ICommonQuery1
exec sp_executesql N'SELECT
[Extent1].[PersonId] AS [PersonId],
[Extent1].[FirstName] AS [FirstName],
[Extent1].[LastName] AS [LastName]
FROM [dbo].[Person] AS [Extent1]
WHERE [Extent1].[PersonId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1
--ICommonQuery2
exec sp_executesql N'SELECT
[Extent1].[PersonId] AS [PersonId],
[Extent1].[FirstName] AS [FirstName],
[Extent1].[LastName] AS [LastName]
FROM [dbo].[Person] AS [Extent1]
WHERE [Extent1].[PersonId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=3
*/
So Sie jetzt einige Fragen haben, lassen Sie mich diejenigen erraten und versuchen, sie
Lets einige herauszufinden, zu beantworten Punkte hier,
alle Anfragen hat einen gemeinsamen Teil
WHERE [Extent1].[PersonId] IN (0,1,2,3)
warum? Da sowohl Funktion IQueryable<Employee> GetEmployeeAndPersonDetailIQueryable
und IEnumerable<Employee> GetEmployeeAndPersonDetailIEnumerable
von SomeServiceClass
ein enthält common line in linq queries
where employeesToCollect.Contains(e.PersonId)
als warum AND (N'M' = [Extent1].[Gender])
Teil in IEnumerable execution part
fehlt, während in Funktion rufen wir Where(i => i.Gender == "M")
in program.cs
verwendet
Jetzt sind wir in dem Punkt, wo der Unterschied zwischen
IQueryable
und kam
Was entity framwork
tut, wenn eine IQueryable
Methode aufgerufen, es linq statement written inside the method
tooks und versucht, wenn more linq/expression is defind on the resultset
, um herauszufinden, es alle LINQ-Abfragen, bis das Ergebnis definiert sammeln müssen holen und constructs more appropriate sql query to execute
.
Es bietet eine Menge Vorteile, wie,
wie hier im Server Beispiel sQL zurückgegeben Anwendung nur two rows after IQueryable execution
aber returned THREE rows for IEnumerable query
warum?
Im Fall der IEnumerable
Methode, entity framework
nahm Linq-Anweisung in der Methode geschrieben und erstellt SQL-Abfrage, wenn Ergebnis abrufen müssen. it does not include rest linq part to constructs the sql query
. Wie hier ist keine Filterung in SQL-Server auf Spalte gender
getan.
Aber die Ausgänge sind gleich? Denn IEnumerable filtert das Ergebnis weiter in der Anwendungsebene nach dem Abrufen des Ergebnisses von sql server
SO, was sollte jemand wählen? Ich persönlich bevorzuge, Funktionsergebnis als IQueryable<T>
zu definieren, weil es viele Vorteile gibt, die es über "IEnumerable" mag, konnten Sie join two or more IQueryable function
, die spezifischeren Index zum sql Server erzeugen.
Hier im Beispiel können Sie sehen, IQueryable Query(IQueryableQuery2)
mehr spezifische Skript als IEnumerable query(IEnumerableQuery2)
generieren, die in my point of view
viel akzeptabler ist.
Wo ist die Definition von "GetQueryableProducts();"? – Pankaj
@StackOverflowUser Es soll eine beliebige Methode sein, die ein 'IQueryable' zurückgibt - wäre spezifisch für Ihr ORM oder Repository usw. –
richtig. aber Sie erwähnten Where-Klausel nach diesem Funktionsaufruf. Das System ist sich des Filters nicht bewusst. Ich meine es holen immer noch alle Rekorde von Produkten ab. Recht? – Pankaj