Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Wenn Sie über eine Anwendung verfügen, die strukturell ähnliche Abfragen in Entity Framework mehrmals ausführt, können Sie die Leistung häufig erhöhen, indem Sie die Abfrage einmal kompilieren und mehrmals mit verschiedenen Parametern ausführen. Eine Anwendung muss beispielsweise alle Kunden in einer bestimmten Stadt abrufen; die Stadt wird zur Laufzeit vom Benutzer in einem Formular angegeben. LINQ to Entities unterstützt die Verwendung kompilierter Abfragen zu diesem Zweck.
Ab .NET Framework 4.5 werden LINQ-Abfragen automatisch zwischengespeichert. Sie können jedoch weiterhin kompilierte LINQ-Abfragen verwenden, um diese Kosten in späteren Ausführungen zu reduzieren und kompilierte Abfragen effizienter zu sein als LINQ-Abfragen, die automatisch zwischengespeichert werden. LINQ to Entities-Abfragen, die den Enumerable.Contains Operator auf In-Memory-Sammlungen anwenden, werden nicht automatisch zwischengespeichert. Außerdem ist das Parametrisieren von In-Memory-Auflistungen in kompilierten LINQ-Abfragen nicht zulässig.
Die CompiledQuery Klasse stellt die Kompilierung und Zwischenspeicherung von Abfragen für die Wiederverwendung bereit. Diese Klasse enthält eine CompiledQuery-Methode einer Compile mit mehreren Überladungen. Rufen Sie die Compile Methode auf, um einen neuen Delegaten für die kompilierte Abfrage zu erstellen. Die Compile-Methoden, bereitgestellt mit einem ObjectContext und Parameterwerten, geben einen Delegaten zurück, der ein Ergebnis erzeugt (wie eine IQueryable<T>-Instanz). Die Abfrage wird nur während der ersten Ausführung einmal kompiliert. Die zum Zeitpunkt der Kompilierung festgelegten Zusammenführungsoptionen für die Abfrage können später nicht mehr geändert werden. Nachdem die Abfrage kompiliert wurde, können Sie nur Parameter des primitiven Typs angeben, aber Sie können keine Teile der Abfrage ersetzen, die das generierte SQL ändern würden. Weitere Informationen finden Sie unter EF Merge Options and Compiled Queries.
Der LINQ to Entities-Abfrageausdruck, den die CompiledQuery-Methode Compile kompiliert, wird durch einen der generischen Func-Delegaten dargestellt, wie Func<T1,T2,T3,T4,TResult>. Der Abfrageausdruck kann höchstens einen ObjectContext Parameter, einen Rückgabeparameter und 16 Abfrageparameter kapseln. Wenn mehr als 16 Abfrageparameter erforderlich sind, können Sie eine Struktur erstellen, deren Eigenschaften Abfrageparameter darstellen. Anschließend können Sie die Eigenschaften für die Struktur im Abfrageausdruck verwenden, nachdem Sie die Eigenschaften festgelegt haben.
Beispiel 1
Das folgende Beispiel kompiliert und ruft dann eine Abfrage auf, die einen Decimal Eingabeparameter akzeptiert und eine Reihe von Bestellungen zurückgibt, bei denen die fällige Summe größer oder gleich 200,00 $ ist.
static readonly Func<AdventureWorksEntities, Decimal, IQueryable<SalesOrderHeader>> s_compiledQuery2 =
CompiledQuery.Compile<AdventureWorksEntities, Decimal, IQueryable<SalesOrderHeader>>(
(ctx, total) => from order in ctx.SalesOrderHeaders
where order.TotalDue >= total
select order);
static void CompiledQuery2()
{
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
Decimal totalDue = 200.00M;
IQueryable<SalesOrderHeader> orders = s_compiledQuery2.Invoke(context, totalDue);
foreach (SalesOrderHeader order in orders)
{
Console.WriteLine($"ID: {order.SalesOrderID} Order date: {order.OrderDate} Total due: {order.TotalDue}");
}
}
}
ReadOnly s_compQuery2 As Func(Of AdventureWorksEntities, Decimal, IQueryable(Of SalesOrderHeader)) = _
CompiledQuery.Compile(Of AdventureWorksEntities, Decimal, IQueryable(Of SalesOrderHeader))( _
Function(ctx As AdventureWorksEntities, total As Decimal) _
From order In ctx.SalesOrderHeaders _
Where (order.TotalDue >= total) _
Select order)
Sub CompiledQuery2()
Using context As New AdventureWorksEntities()
Dim totalDue As Decimal = 200.0
Dim orders As IQueryable(Of SalesOrderHeader) = s_compQuery2.Invoke(context, totalDue)
For Each order In orders
Console.WriteLine("ID: {0} Order date: {1} Total due: {2}", _
order.SalesOrderID, _
order.OrderDate, _
order.TotalDue)
Next
End Using
End Sub
Beispiel 2
Das folgende Beispiel kompiliert und ruft dann eine Abfrage auf, die eine ObjectQuery<T> Instanz zurückgibt:
static readonly Func<AdventureWorksEntities, ObjectQuery<SalesOrderHeader>> s_compiledQuery1 =
CompiledQuery.Compile<AdventureWorksEntities, ObjectQuery<SalesOrderHeader>>(
ctx => ctx.SalesOrderHeaders);
static void CompiledQuery1_MQ()
{
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
IQueryable<SalesOrderHeader> orders = s_compiledQuery1.Invoke(context);
foreach (SalesOrderHeader order in orders)
Console.WriteLine(order.SalesOrderID);
}
}
ReadOnly s_compQuery1 As Func(Of AdventureWorksEntities, ObjectQuery(Of SalesOrderHeader)) = _
CompiledQuery.Compile(Of AdventureWorksEntities, ObjectQuery(Of SalesOrderHeader))( _
Function(ctx) ctx.SalesOrderHeaders)
Sub CompiledQuery1_MQ()
Using context As New AdventureWorksEntities()
Dim orders As ObjectQuery(Of SalesOrderHeader) = s_compQuery1.Invoke(context)
For Each order In orders
Console.WriteLine(order.SalesOrderID)
Next
End Using
End Sub
Beispiel 3
Im folgenden Beispiel wird eine Abfrage kompiliert und aufgerufen, die den Mittelwert der Produktlistenpreise als Decimal Wert zurückgibt:
static readonly Func<AdventureWorksEntities, Decimal> s_compiledQuery3MQ = CompiledQuery.Compile<AdventureWorksEntities, Decimal>(
ctx => ctx.Products.Average(product => product.ListPrice));
static void CompiledQuery3_MQ()
{
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
Decimal averageProductPrice = s_compiledQuery3MQ.Invoke(context);
Console.WriteLine($"The average of the product list prices is $: {averageProductPrice}");
}
}
Using context As New AdventureWorksEntities()
Dim compQuery = CompiledQuery.Compile(Of AdventureWorksEntities, Decimal)( _
Function(ctx) ctx.Products.Average(Function(Product) Product.ListPrice))
Dim averageProductPrice As Decimal = compQuery.Invoke(context)
Console.WriteLine("The average of the product list prices is $: {0}", averageProductPrice)
End Using
Beispiel 4
Das folgende Beispiel kompiliert und ruft dann eine Abfrage auf, die einen String Eingabeparameter akzeptiert, und gibt dann eine Contact E-Mail-Adresse zurück, deren E-Mail-Adresse mit der angegebenen Zeichenfolge beginnt:
static readonly Func<AdventureWorksEntities, string, Contact> s_compiledQuery4MQ =
CompiledQuery.Compile<AdventureWorksEntities, string, Contact>(
(ctx, name) => ctx.Contacts.First(contact => contact.EmailAddress.StartsWith(name)));
static void CompiledQuery4_MQ()
{
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
string contactName = "caroline";
Contact foundContact = s_compiledQuery4MQ.Invoke(context, contactName);
Console.WriteLine($"An email address starting with 'caroline': {foundContact.EmailAddress}");
}
}
Using context As New AdventureWorksEntities()
Dim compQuery = CompiledQuery.Compile(Of AdventureWorksEntities, String, Contact)( _
Function(ctx, name) ctx.Contacts.First(Function(contact) contact.EmailAddress.StartsWith(name)))
Dim contactName As String = "caroline"
Dim foundContact As Contact = compQuery.Invoke(context, contactName)
Console.WriteLine("An email address starting with 'caroline': {0}", _
foundContact.EmailAddress)
End Using
Beispiel 5
Im folgenden Beispiel wird eine Abfrage kompiliert und dann aufgerufen, die DateTime und Decimal als Eingabeparameter akzeptiert und eine Reihe von Aufträgen zurückgibt, bei denen das Bestelldatum nach dem 8. März 2003 liegt und der Gesamtbetrag weniger als $300.00 beträgt.
static readonly Func<AdventureWorksEntities, DateTime, Decimal, IQueryable<SalesOrderHeader>> s_compiledQuery5 =
CompiledQuery.Compile<AdventureWorksEntities, DateTime, Decimal, IQueryable<SalesOrderHeader>>(
(ctx, orderDate, totalDue) => from product in ctx.SalesOrderHeaders
where product.OrderDate > orderDate
&& product.TotalDue < totalDue
orderby product.OrderDate
select product);
static void CompiledQuery5()
{
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
DateTime date = new DateTime(2003, 3, 8);
Decimal amountDue = 300.00M;
IQueryable<SalesOrderHeader> orders = s_compiledQuery5.Invoke(context, date, amountDue);
foreach (SalesOrderHeader order in orders)
{
Console.WriteLine($"ID: {order.SalesOrderID} Order date: {order.OrderDate} Total due: {order.TotalDue}");
}
}
}
ReadOnly s_compQuery5 = _
CompiledQuery.Compile(Of AdventureWorksEntities, DateTime, Decimal, IQueryable(Of SalesOrderHeader))( _
Function(ctx, orderDate, totalDue) From product In ctx.SalesOrderHeaders _
Where product.OrderDate > orderDate _
And product.TotalDue < totalDue _
Order By product.OrderDate _
Select product)
Sub CompiledQuery5()
Using context As New AdventureWorksEntities()
Dim orderedAfterDate As DateTime = New DateTime(2003, 3, 8)
Dim amountDue As Decimal = 300.0
Dim orders As IQueryable(Of SalesOrderHeader) = _
s_compQuery5.Invoke(context, orderedAfterDate, amountDue)
For Each order In orders
Console.WriteLine("ID: {0} Order date: {1} Total due: {2}", _
order.SalesOrderID, order.OrderDate, order.TotalDue)
Next
End Using
End Sub
Beispiel 6
Im folgenden Beispiel wird eine Abfrage kompiliert und aufgerufen, die einen DateTime Eingabeparameter akzeptiert und eine Reihenfolge von Bestellungen zurückgibt, bei denen das Bestelldatum später als der 8. März 2004 liegt. Diese Abfrage gibt die Bestellinformationen als Abfolge anonymer Typen zurück. Anonyme Typen werden vom Compiler abgeleitet, sodass Sie keine Typparameter in der CompiledQueryMethode 's Compile ' angeben können und der Typ in der Abfrage selbst definiert ist.
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
var compiledQuery = CompiledQuery.Compile((AdventureWorksEntities ctx, DateTime orderDate) =>
from order in ctx.SalesOrderHeaders
where order.OrderDate > orderDate
select new {order.OrderDate, order.SalesOrderID, order.TotalDue});
DateTime date = new DateTime(2004, 3, 8);
var results = compiledQuery.Invoke(context, date);
foreach (var order in results)
{
Console.WriteLine($"ID: {order.SalesOrderID} Order date: {order.OrderDate} Total due: {order.TotalDue}");
}
}
Using context As New AdventureWorksEntities()
Dim compQuery = CompiledQuery.Compile( _
Function(ctx As AdventureWorksEntities, orderDate As DateTime) _
From order In ctx.SalesOrderHeaders _
Where order.OrderDate > orderDate _
Select New With {order.OrderDate, order.SalesOrderID, order.TotalDue})
Dim orderedAfterDate As DateTime = New DateTime(2004, 3, 8)
Dim orders = compQuery.Invoke(context, orderedAfterDate)
For Each order In orders
Console.WriteLine("ID: {0} Order date: {1} Total due: {2}", _
order.SalesOrderID, order.OrderDate, order.TotalDue)
Next
End Using
Beispiel 7
Im folgenden Beispiel wird eine Abfrage kompiliert und aufgerufen, die einen benutzerdefinierten Struktureingabeparameter akzeptiert und eine Reihenfolge von Bestellungen zurückgibt. Die Struktur definiert Startdatum, Enddatum und Abfrageparameter insgesamt, und die Abfrage gibt Bestellungen zurück, die zwischen dem 3. märz und dem 8. März 2003 mit einer Gesamtfälligkeit von mehr als 700,00 $ geliefert wurden.
static Func<AdventureWorksEntities, MyParams, IQueryable<SalesOrderHeader>> s_compiledQuery =
CompiledQuery.Compile<AdventureWorksEntities, MyParams, IQueryable<SalesOrderHeader>>(
(ctx, myparams) => from sale in ctx.SalesOrderHeaders
where sale.ShipDate > myparams.startDate && sale.ShipDate < myparams.endDate
&& sale.TotalDue > myparams.totalDue
select sale);
static void CompiledQuery7()
{
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
MyParams myParams = new MyParams();
myParams.startDate = new DateTime(2003, 3, 3);
myParams.endDate = new DateTime(2003, 3, 8);
myParams.totalDue = 700.00M;
IQueryable<SalesOrderHeader> sales = s_compiledQuery.Invoke(context, myParams);
foreach (SalesOrderHeader sale in sales)
{
Console.WriteLine($"ID: {sale.SalesOrderID}");
Console.WriteLine($"Ship date: {sale.ShipDate}");
Console.WriteLine($"Total due: {sale.TotalDue}");
}
}
}
ReadOnly s_compQuery = CompiledQuery.Compile(Of AdventureWorksEntities, MyParams, IQueryable(Of SalesOrderHeader))( _
Function(ctx, mySearchParams) _
From sale In ctx.SalesOrderHeaders _
Where sale.ShipDate > mySearchParams.startDate _
And sale.ShipDate < mySearchParams.endDate _
And sale.TotalDue > mySearchParams.totalDue _
Select sale)
Sub CompiledQuery7()
Using context As New AdventureWorksEntities()
Dim myParams As MyParams = New MyParams()
myParams.startDate = New DateTime(2003, 3, 3)
myParams.endDate = New DateTime(2003, 3, 8)
myParams.totalDue = 700.0
Dim sales = s_compQuery.Invoke(context, myParams)
For Each sale In sales
Console.WriteLine("ID: {0}", sale.SalesOrderID)
Console.WriteLine("Ship date: {0}", sale.ShipDate)
Console.WriteLine("Total due: {0}", sale.TotalDue)
Next
End Using
End Sub
Die Struktur, die die Abfrageparameter definiert:
struct MyParams
{
public DateTime startDate;
public DateTime endDate;
public decimal totalDue;
}
Public Structure MyParams
Public startDate As DateTime
Public endDate As DateTime
Public totalDue As Decimal
End Structure