Lefordított lekérdezések (LINQ–Entitások)
Ha olyan alkalmazással rendelkezik, amely szerkezetileg hasonló lekérdezéseket hajt végre többször az Entity Frameworkben, gyakran növelheti a teljesítményt azáltal, hogy egyszer összeállítja a lekérdezést, és többször végrehajtja azt különböző paraméterekkel. Előfordulhat például, hogy egy alkalmazásnak le kell kérnie egy adott város összes ügyfelet; a várost futásidőben adja meg a felhasználó egy űrlapon. A LINQ to Entities támogatja a lefordított lekérdezések használatát erre a célra.
A 4.5-ös .NET-keretrendszer kezdve a LINQ-lekérdezések automatikusan gyorsítótárazva lesznek. A lefordított LINQ-lekérdezésekkel azonban csökkentheti ezt a költséget a későbbi végrehajtásokban, és a lefordított lekérdezések hatékonyabbak lehetnek, mint az automatikusan gyorsítótárazott LINQ-lekérdezések. A linq to Entities lekérdezések, amelyek az Enumerable.Contains
operátort a memóriabeli gyűjteményekre alkalmazzák, nem lesznek automatikusan gyorsítótárazva. Emellett a memóriabeli gyűjtemények paraméterezése a lefordított LINQ-lekérdezésekben nem engedélyezett.
Az CompiledQuery osztály a lekérdezések összeállítását és gyorsítótárazását biztosítja az újrafelhasználáshoz. Elméletileg ez az osztály egy CompiledQuerytöbb Compile
túlterheléssel rendelkező metódust tartalmaz. Hívja meg a Compile
metódust, hogy hozzon létre egy új meghatalmazottat a lefordított lekérdezés megjelenítéséhez. Az Compile
egy és paraméterértékekkel ObjectContext ellátott metódusok egy olyan delegáltat adnak vissza, amely valamilyen eredményt hoz létre (például egy példányt IQueryable<T> ). A lekérdezés csak az első végrehajtás során egyszer fordít le. A lekérdezéshez a fordítás időpontjában beállított egyesítési beállítások később nem módosíthatók. A lekérdezés fordítása után csak primitív típusú paramétereket adhat meg, de nem helyettesítheti a lekérdezés azon részeit, amelyek megváltoztatnák a létrehozott SQL-t. További információ: EF Merge Options and Compiled Queries.
A LINQ to Entities lekérdezési kifejezés, amelyet a CompiledQuerymetódus Compile
lefordít, az egyik általános Func
meghatalmazott képviseli, például Func<T1,T2,T3,T4,TResult>. A lekérdezési kifejezés legfeljebb egy ObjectContext
paramétert, egy visszatérési paramétert és 16 lekérdezési paramétert tartalmazhat. Ha több mint 16 lekérdezési paraméterre van szükség, létrehozhat egy struktúrát, amelynek tulajdonságai lekérdezési paramétereket jelölnek. Ezután a tulajdonságok megadása után használhatja a szerkezet tulajdonságait a lekérdezési kifejezésben.
1. példa
Az alábbi példa lefordít egy lekérdezést, majd meghív egy olyan lekérdezést, amely elfogadja a Decimal bemeneti paramétert, és olyan sorrendsort ad vissza, amelyben a teljes esedékesség nagyobb vagy egyenlő, mint 200,00 USD:
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: {0} Order date: {1} Total due: {2}",
order.SalesOrderID,
order.OrderDate,
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
2. példa
Az alábbi példa lefordítja, majd meghív egy példányt visszaadó lekérdezést ObjectQuery<T> :
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
3. példa
Az alábbi példa lefordítja, majd meghív egy lekérdezést, amely a terméklista árainak átlagát adja vissza értékként Decimal :
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 $: {0}", 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
4. példa
Az alábbi példa lefordítja, majd meghív egy lekérdezést, amely elfogadja a String bemeneti paramétert, majd visszaad egy Contact
olyan e-mail-címet, amelynek az e-mail-címe a megadott sztringgel kezdődik:
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': {0}",
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
5. példa
Az alábbi példa lefordítja és meghív egy lekérdezést, amely elfogadja DateTime és Decimal bemeneti paramétereket ad vissza, és olyan rendeléssorozatot ad vissza, amelyben a rendelés dátuma 2003. március 8-nál későbbi, és a teljes esedékesség kisebb, mint 300,00 USD:
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: {0} Order date: {1} Total due: {2}", order.SalesOrderID, order.OrderDate, 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
6. példa
Az alábbi példa lefordít egy lekérdezést, majd meghív egy lekérdezést, amely elfogadja a DateTime bemeneti paramétert, és egy rendeléssorozatot ad vissza, ahol a rendelés dátuma 2004. március 8-nál későbbi. Ez a lekérdezés névtelen típusok sorozataként adja vissza a rendelési adatokat. A fordító névtelen típusokra hivatkozik, így a metódusban CompiledQueryCompile
nem adhat meg típusparamétereket, és a típus maga a lekérdezésben van definiálva.
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: {0} Order date: {1} Total due: {2}", order.SalesOrderID, order.OrderDate, 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
7. példa
Az alábbi példa lefordítja, majd meghív egy lekérdezést, amely elfogadja a felhasználó által definiált struktúra bemeneti paraméterét, és megrendelések sorozatát adja vissza. A struktúra meghatározza a kezdő dátumot, a befejezési dátumot és a teljes esedékes lekérdezési paramétereket, a lekérdezés pedig a 2003. március 3. és március 8. között kiszállított rendeléseket adja vissza 700,00 USD-nél nagyobb esedékességgel.
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: {0}", sale.SalesOrderID);
Console.WriteLine("Ship date: {0}", sale.ShipDate);
Console.WriteLine("Total due: {0}", 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
A lekérdezési paramétereket meghatározó struktúra:
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