Sorgu Yürütme

Bir kullanıcı tarafından LINQ sorgusu oluşturulduktan sonra komut ağacına dönüştürülür. Komut ağacı, Entity Framework ile uyumlu bir sorgunun gösterimidir. Ardından komut ağacı veri kaynağına karşı yürütülür. Sorgu yürütme zamanında, sonuç gerçekleştirmede kullanılan ifadeler de dahil olmak üzere tüm sorgu ifadeleri (sorgunun tüm bileşenleri) değerlendirilir.

Sorgu ifadelerinin hangi noktada yürütülebileceği farklılık gösterebilir. SORGU değişkeni oluşturulduğunda değil, sorgu değişkeni yinelendiğinde LINQ sorguları her zaman yürütülür. Buna ertelenmiş yürütme denir. Sorgu sonuçlarını önbelleğe almak için yararlı olan sorguyu hemen yürütülmeye de zorlayabilirsiniz. Bu konu başlığında daha sonra açıklanmıştır.

LinQ to Entities sorgusu yürütürken, sorgudaki bazı ifadeler sunucuda yürütülebilir ve bazı bölümler istemcide yerel olarak yürütülebilir. Bir ifadenin istemci tarafı değerlendirmesi, sorgu sunucuda yürütülmeden önce gerçekleşir. İstemcide bir ifade değerlendirilirse, bu değerlendirmenin sonucu sorgudaki ifadeyle değiştirilir ve sorgu sunucuda yürütülür. Sorgular veri kaynağında yürütülürken, veri kaynağı yapılandırması istemcide belirtilen davranışı geçersiz kılar. Örneğin, null değer işleme ve sayısal duyarlık sunucu ayarlarına bağlıdır. Sunucuda sorgu yürütme sırasında oluşturulan tüm özel durumlar doğrudan istemciye geçirilir.

İpucu

Bir işlecin yürütme davranışını hızla tanımlamanızı sağlayan tablo biçimindeki sorgu işleçlerinin kolay bir özeti için bkz . Standart Sorgu İşleçlerinin Yürütme Biçimine Göre Sınıflandırması (C#).

Ertelenen sorgu yürütme

Bir dizi değer döndüren bir sorguda, sorgu değişkeninin kendisi hiçbir zaman sorgu sonuçlarını tutmaz ve yalnızca sorgu komutlarını depolar. Sorgunun yürütülmesi, sorgu değişkeni bir foreach veya For Each döngüsünde yinelene kadar ertelenmiş olur. Bu, ertelenen yürütme olarak bilinir; başka bir ifadeyle sorgunun yürütülmesi, sorgu oluşturulduğunda bir süre sonra gerçekleşir. Bu, bir sorguyu istediğiniz sıklıkta yürütebileceğiniz anlamına gelir. Bu, örneğin diğer uygulamalar tarafından güncelleştirilen bir veritabanınız olduğunda kullanışlıdır. Uygulamanızda, en son bilgileri almak için bir sorgu oluşturabilir ve her seferinde güncelleştirilmiş bilgileri döndürerek sorguyu tekrar tekrar yürütebilirsiniz.

Ertelenmiş yürütme, birden çok sorguyu birleştirmeye veya bir sorguyu uzatmaya olanak tanır. Bir sorgu genişletildiğinde, yeni işlemleri içerecek şekilde değiştirilir ve nihai yürütme değişiklikleri yansıtır. Aşağıdaki örnekte, ilk sorgu tüm ürünleri döndürür. İkinci sorgu, "L" boyutundaki tüm ürünleri döndürmek için kullanarak Where ilk sorguyu genişletir:

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    IQueryable<Product> productsQuery =
        from p in context.Products
        select p;

    IQueryable<Product> largeProducts = productsQuery.Where(p => p.Size == "L");

    Console.WriteLine("Products of size 'L':");
    foreach (var product in largeProducts)
    {
        Console.WriteLine(product.Name);
    }
}
Using context As New AdventureWorksEntities()
    Dim productsQuery = _
        From p In context.Products _
        Select p

    Dim largeProducts = _
        productsQuery.Where(Function(p) p.Size = "L")

    Console.WriteLine("Products of size 'L':")
    For Each product In largeProducts
        Console.WriteLine(product.Name)
    Next
End Using

Bir sorgu yürütüldükten sonra, ardışık tüm sorgular bellek içi LINQ işleçlerini kullanır. Veya For Each deyimini kullanarak foreach veya LINQ dönüştürme işleçlerinden birini çağırarak sorgu değişkeni üzerinde yinelemek anında yürütmeye neden olur. Bu dönüştürme işleçleri şunlardır: ToList, ToArray, ToLookupve ToDictionary.

Anında Sorgu Yürütme

Bir dizi değer üreten sorguların ertelenmiş yürütülmesinin aksine, tek değer döndüren sorgular hemen yürütülür. Tekil sorgulara Averageörnek olarak , Count, Firstve verilebilir Max. Sorgunun tekil sonucu hesaplamak için bir dizi oluşturması gerektiğinden, bunlar hemen yürütülür. Ayrıca, anında yürütmeyi zorlayabilirsiniz. Bu, bir sorgunun sonuçlarını önbelleğe almak istediğinizde kullanışlıdır. Tek değer üretmeyen bir sorgunun hemen yürütülmesini zorlamak için, bir sorgu veya sorgu değişkeninde yöntemini, ToDictionary yöntemini veya ToArray yöntemini çağırabilirsinizToList. Aşağıdaki örnek, bir diziyi ToArray hemen bir dizi olarak değerlendirmek için yöntemini kullanır.

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    ObjectSet<Product> products = context.Products;

    Product[] prodArray = (
        from product in products
        orderby product.ListPrice descending
        select product).ToArray();

    Console.WriteLine("Every price from highest to lowest:");
    foreach (Product product in prodArray)
    {
        Console.WriteLine(product.ListPrice);
    }
}
Using context As New AdventureWorksEntities
    Dim products As ObjectSet(Of Product) = context.Products

    Dim prodArray As Product() = ( _
        From product In products _
        Order By product.ListPrice Descending _
        Select product).ToArray()

    Console.WriteLine("The list price from highest to lowest:")
    For Each prod As Product In prodArray
        Console.WriteLine(prod.ListPrice)
    Next
End Using

Ayrıca, sorgu ifadesinin foreach hemen arkasına veya For Each döngüsünü koyarak, ancak çağırarak ToList veya ToArray tüm verileri tek bir koleksiyon nesnesinde önbelleğe alarak yürütmeyi zorlayabilirsiniz.

Depolama Yürütmesi

Genel olarak, LINQ to Entities ifadeleri sunucuda değerlendirilir ve ifadenin davranışının ortak dil çalışma zamanı (CLR) semantiğini değil, veri kaynağının davranışlarını izlemesi beklenmemelidir. Bununla birlikte, ifadenin istemcide yürütülmesi gibi özel durumlar vardır. Bu, örneğin sunucu ve istemci farklı saat dilimlerinde olduğunda beklenmeyen sonuçlara neden olabilir.

Sorgudaki bazı ifadeler istemcide yürütülebilir. Genel olarak, sorgu yürütmenin çoğunun sunucuda gerçekleşmesi beklenir. Veri kaynağına eşlenen sorgu öğelerine karşı yürütülen yöntemlerin yanı sıra, sorguda genellikle yerel olarak yürütülebilen ifadeler vardır. Sorgu ifadesinin yerel olarak yürütülmesi, sorgu yürütme veya sonuç oluşturmada kullanılabilecek bir değer verir.

Değerlerin bağlanması, alt ifadeler, kapanışlardan alt sorgular ve nesnelerin sorgu sonuçlarına gerçekleştirilmesi gibi bazı işlemler her zaman istemcide yürütülür. Bunun net etkisi, bu öğelerin (örneğin parametre değerleri) yürütme sırasında güncelleştirilememesidir. Anonim türler veri kaynağında satır içinde oluşturulabilir, ancak bunu yapmak için varsayılmamalıdır. Satır içi gruplandırmalar veri kaynağında da oluşturulabilir, ancak bu her örnekte varsayılmamalıdır. Genel olarak, sunucuda nelerin oluşturulduğunda herhangi bir varsayımda bulunmamak en iyisidir.

Bu bölümde, kodun istemcide yerel olarak yürütüldiği senaryolar açıklanmaktadır. Hangi ifade türlerinin yerel olarak yürütüldiği hakkında daha fazla bilgi için bkz . LINQ to Entities Queries içindeki ifadeler.

Değişmez Değerler ve Parametreler

Aşağıdaki örnekteki orderID değişken gibi yerel değişkenler istemcide değerlendirilir.

int orderID = 51987;

IQueryable<SalesOrderHeader> salesInfo =
    from s in context.SalesOrderHeaders
    where s.SalesOrderID == orderID
    select s;
Dim orderID As Integer = 51987

Dim salesInfo = _
    From s In context.SalesOrderHeaders _
    Where s.SalesOrderID = orderID _
    Select s

Yöntem parametreleri de istemcide değerlendirilir. orderID Aşağıdaki yöntemine MethodParameterExample geçirilen parametre bir örnektir.

public static void MethodParameterExample(int orderID)
{
    using (AdventureWorksEntities context = new AdventureWorksEntities())
    {

        IQueryable<SalesOrderHeader> salesInfo =
            from s in context.SalesOrderHeaders
            where s.SalesOrderID == orderID
            select s;

        foreach (SalesOrderHeader sale in salesInfo)
        {
            Console.WriteLine("OrderID: {0}, Total due: {1}", sale.SalesOrderID, sale.TotalDue);
        }
    }
}
Function MethodParameterExample(ByVal orderID As Integer)
    Using context As New AdventureWorksEntities()

        Dim salesInfo = _
            From s In context.SalesOrderHeaders _
            Where s.SalesOrderID = orderID _
            Select s

        Console.WriteLine("Sales order info:")
        For Each sale As SalesOrderHeader In salesInfo
            Console.WriteLine("OrderID: {0}, Total due: {1}", sale.SalesOrderID, sale.TotalDue)
        Next
    End Using

End Function

İstemcide Değişmez Değerleri Atama

null bir CLR türüne atama, istemcide yürütülür:

IQueryable<Contact> query =
    from c in context.Contacts
    where c.EmailAddress == (string)null
    select c;
Dim query = _
    From c In context.Contacts _
    Where c.EmailAddress = CType(Nothing, String) _
    Select c

Null atanabilir Decimalgibi bir türe dönüştürme, istemcide yürütülür:

var weight = (decimal?)23.77;
IQueryable<Product> query =
    from product in context.Products
    where product.Weight == weight
    select product;
Dim weight = CType(23.77, Decimal?)
Dim query = _
    From product In context.Products _
    Where product.Weight = weight _
    Select product

Değişmez Değerler için Oluşturucular

Kavramsal model türlerine eşlenebilen yeni CLR türleri istemcide yürütülür:

var weight = new decimal(23.77);
IQueryable<Product> query =
    from product in context.Products
    where product.Weight == weight
    select product;
Dim weight = New Decimal(23.77)
Dim query = _
    From product In context.Products _
    Where product.Weight = weight _
    Select product

Yeni diziler de istemcide yürütülür.

Özel Durumları Depolama

Sorgu yürütme sırasında karşılaşılan tüm depo hataları istemciye geçirilir ve eşlenmez veya işlenmez.

Depolama Yapılandırması

Sorgu depoda yürütürken, depo yapılandırması tüm istemci davranışlarını geçersiz kılar ve tüm işlemler ve ifadeler için depo semantiği ifade edilir. Bu, CLR ile depolama yürütmesi arasında null karşılaştırmalar, GUID sıralaması, hassas olmayan veri türleri (kayan nokta türleri veya DateTimegibi) ve dize işlemleri içeren işlemlerin duyarlığı ve doğruluğu gibi alanlarda davranışta farka neden olabilir. Sorgu sonuçlarını incelerken bunu göz önünde bulundurmak önemlidir.

Örneğin, CLR ile SQL Server arasındaki davranış farklılıkları şunlardır:

  • SQL Server GUID'leri CLR'den farklı bir şekilde sipariş eder.

  • SQL Server'da Ondalık türüyle ilgilenirken sonuç duyarlığında farklılıklar da olabilir. Bunun nedeni SQL Server ondalık türünün sabit duyarlık gereksinimleridir. Örneğin, istemcideki bellekte 0,0, 0,0 ve 1,0 değerlerinin ortalaması Decimal 0,3333333333333333333333, ancak depodaki 0,3333333 'dür (SQL Server'ın ondalık türü için varsayılan duyarlığı temel alır).

  • Bazı dize karşılaştırma işlemleri de SQL Server'da CLR'ye göre farklı işlenir. Dize karşılaştırma davranışı, sunucudaki harmanlama ayarlarına bağlıdır.

  • İŞLEV veya yöntem çağrıları, LINQ to Entities sorgusuna dahil edildiğinde, Entity Framework'teki kurallı işlevlerle eşlenir ve daha sonra Transact-SQL'e çevrilir ve SQL Server veritabanında yürütülür. Bu eşlenen işlevlerin sergilendiği davranışın temel sınıf kitaplıklarındaki uygulamadan farklı olabileceği durumlar vardır. Örneğin, parametre olarak boş bir dizeyle , StartsWithve yöntemlerini çağırmak ContainsCLR'de yürütülürken döndürülürtrue, ancak SQL Server'da yürütülürken döndürülür falseEndsWith. EndsWith SQL Server iki dizeyi yalnızca sondaki boşlukta farklıysa eşit olarak kabul ettiğinden, CLR bunların eşit olmadığını düşündüğü için yöntemi farklı sonuçlar da döndürebilir. Bu, aşağıdaki örnekte gösterilmiştir:

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    IQueryable<string> query = from p in context.Products
                               where p.Name == "Reflector"
                               select p.Name;

    IEnumerable<bool> q = query.Select(c => c.EndsWith("Reflector "));

    Console.WriteLine("LINQ to Entities returns: " + q.First());
    Console.WriteLine("CLR returns: " + "Reflector".EndsWith("Reflector "));
}
Using context As New AdventureWorksEntities()

    Dim query = _
        From p In context.Products _
        Where p.Name = "Reflector" _
        Select p.Name

    Dim q = _
        query.Select(Function(c) c.EndsWith("Reflector "))

    Console.WriteLine("LINQ to Entities returns: " & q.First())
    Console.WriteLine("CLR returns: " & "Reflector".EndsWith("Reflector "))
End Using