Kueri yang dikompilasi (LINQ ke Entitas)
Ketika Anda memiliki aplikasi yang menjalankan kueri serupa secara struktural berkali-kali dalam Kerangka Kerja Entitas, Anda dapat sering meningkatkan performa dengan mengompilasi kueri satu kali dan mengeksekusinya beberapa kali dengan parameter yang berbeda. Misalnya, aplikasi mungkin harus mengambil semua pelanggan di kota tertentu; kota ditentukan pada durasi oleh pengguna dalam formulir. LINQ ke Entitas mendukung penggunaan kueri yang dikompilasi untuk tujuan ini.
Dimulai dengan .NET Framework 4.5, kueri LINQ di-cache secara otomatis. Namun, Anda masih dapat menggunakan kueri LINQ yang dikompilasi untuk mengurangi biaya ini dalam eksekusi nanti dan kueri yang dikompilasi dapat lebih efisien daripada kueri LINQ yang secara otomatis di-cache. LINQ ke kueri Entitas yang menerapkan operator Enumerable.Contains
ke koleksi dalam memori tidak di-cache secara otomatis. Selain itu, parameterisasi koleksi dalam memori dalam kueri LINQ yang dikompilasi tidak diperbolehkan.
Kelas CompiledQuery menyediakan kompilasi dan penembolokan kueri untuk digunakan kembali. Secara konseptual, kelas ini berisi metode CompiledQueryCompile
dengan beberapa kelebihan beban. Panggil metode Compile
untuk membuat delegasi baru untuk mewakili kueri yang dikompilasi. Metode Compile
, yang disediakan dengan nilai parameter dan ObjectContext, mengembalikan delegasi yang menghasilkan beberapa hasil (seperti instans IQueryable<T>). Kueri dikompilasi sekali selama hanya eksekusi pertama. Opsi penggabungan yang diatur untuk kueri pada saat kompilasi tidak dapat diubah nanti. Setelah kueri dikompilasi, Anda hanya dapat menyediakan parameter jenis primitif tetapi Anda tidak dapat mengganti bagian kueri yang akan mengubah SQL yang dihasilkan. Untuk informasi selengkapnya, lihat Opsi Penggabungan EF dan Kueri yang Dikompilasi.
Ekspresi kueri LINQ ke Entitas yang dikompilasi metode CompiledQueryCompile
diwakili oleh salah satu delegasi generik Func
, seperti Func<T1,T2,T3,T4,TResult>. Paling banyak, ekspresi kueri dapat merangkum parameter ObjectContext
, parameter pengembalian, dan 16 parameter kueri. Jika diperlukan lebih dari 16 parameter kueri, Anda dapat membuat struktur yang propertinya mewakili parameter kueri. Anda kemudian dapat menggunakan properti pada struktur dalam ekspresi kueri setelah Anda mengatur properti.
Contoh 1
Contoh berikut mengompilasi lalu memanggil kueri yang menerima parameter input Decimal dan mengembalikan urutan pesanan di mana total yang jatuh tempo lebih besar dari atau sama dengan $200,00:
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
Contoh 2
Contoh berikut mengompilasi lalu memanggil kueri yang mengembalikan instans 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
Contoh 3
Contoh berikut mengompilasi lalu memanggil kueri yang mengembalikan rata-rata harga daftar produk sebagai nilai 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
Contoh 4
Contoh berikut mengompilasi lalu memanggil kueri yang menerima String parameter input lalu mengembalikan Contact
alamat email yang dimulai dengan string yang ditentukan:
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
Contoh 5
Contoh berikut mengompilasi lalu memanggil kueri yang menerima DateTime dan Decimal memasukkan parameter dan mengembalikan urutan pesanan di mana tanggal pesanan lebih lambat dari 8 Maret 2003, dan total jatuh tempo kurang dari $300,00:
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
Contoh 6
Contoh berikut mengompilasi lalu memanggil kueri yang menerima parameter input DateTime dan mengembalikan urutan pesanan di mana total yang jatuh tempo lebih besar dari atau sama dengan $8, 2004. Kueri ini mengembalikan informasi pesanan sebagai urutan jenis anonim. Jenis anonim disimpulkan oleh kompilator, sehingga Anda tidak dapat menentukan parameter jenis dalam metode CompiledQueryCompile
dan jenis didefinisikan dalam kueri itu sendiri.
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
Contoh 7
Contoh berikut mengompilasi lalu memanggil kueri yang menerima parameter input struktur yang ditentukan pengguna dan mengembalikan urutan pesanan. Struktur menentukan tanggal mulai, tanggal akhir, dan total parameter kueri jatuh tempo, dan kueri mengembalikan pesanan yang dikirim antara 3 Maret dan 8 Maret 2003 dengan total jatuh tempo lebih besar dari $700,00.
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
Struktur yang menentukan parameter kueri:
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