Udostępnij za pośrednictwem


Znane problemy i zagadnienia dotyczące składnika LINQ to Entities

Ta sekcja zawiera informacje o znanych problemach z zapytaniami LINQ to Entities.

Zapytania LINQ, których nie można buforować

Począwszy od programu .NET Framework 4.5, zapytania LINQ to Entities są automatycznie buforowane. Jednak zapytania LINQ to Entities, które stosują Enumerable.Contains operator do kolekcji w pamięci, nie są automatycznie buforowane. Ponadto parametryzacja kolekcji w pamięci w skompilowanych zapytaniach LINQ nie jest dozwolona.

Utracono informacje dotyczące zamawiania

Rzutowanie kolumn w typ anonimowy spowoduje utratę informacji o kolejności w niektórych zapytaniach wykonywanych względem bazy danych programu SQL Server 2005 ustawionego na poziom zgodności "80". Dzieje się tak, gdy nazwa kolumny na liście order-by pasuje do nazwy kolumny w selektorze, jak pokazano w poniższym przykładzie:

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    // Ordering information is lost when executed against a SQL Server 2005
    // database running with a compatibility level of "80".
    var results = context.Contacts.SelectMany(c => c.SalesOrderHeaders)
        .OrderBy(c => c.SalesOrderDetails.Count)
        .Select(c => new { c.SalesOrderDetails.Count });

    foreach (var result in results)
        Console.WriteLine(result.Count);
}
Using context As New AdventureWorksEntities()
    ' Ordering information is lost when executed against a SQL Server 2005
    ' database running with a compatibility level of "80".
    Dim results = context.Contacts.SelectMany(Function(c) c.SalesOrderHeaders) _
        .OrderBy(Function(c) c.SalesOrderDetails.Count) _
        .Select(Function(c) New With {c.SalesOrderDetails.Count})

    For Each result In results
        Console.WriteLine(result.Count)
    Next
End Using

Niepodpisane liczby całkowite nieobsługiwane

Określanie typu niepodpisanej liczby całkowitej w zapytaniu LINQ to Entities nie jest obsługiwane, ponieważ platforma Entity Framework nie obsługuje niepodpisanych liczb całkowitych. Jeśli określisz niepodpisaną liczbę całkowitą, ArgumentException podczas tłumaczenia wyrażenia zapytania zostanie zgłoszony wyjątek, jak pokazano w poniższym przykładzie. W tym przykładzie zapytania dotyczące zamówienia o identyfikatorze 48000.

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    uint s = UInt32.Parse("48000");

    IQueryable<SalesOrderDetail> query = from sale in context.SalesOrderDetails
                                         where sale.SalesOrderID == s
                                         select sale;

    // NotSupportedException exception is thrown here.
    try
    {
        foreach (SalesOrderDetail order in query)
            Console.WriteLine("SalesOrderID: " + order.SalesOrderID);
    }
    catch (NotSupportedException ex)
    {
        Console.WriteLine("Exception: {0}", ex.Message);
    }
}
Using context As New AdventureWorksEntities()
    Dim saleId As UInteger = UInt32.Parse("48000")

    Dim query = _
        From sale In context.SalesOrderDetails _
        Where sale.SalesOrderID = saleId _
        Select sale

    Try
        ' NotSupportedException exception is thrown here.
        For Each order As SalesOrderDetail In query
            Console.WriteLine("SalesOrderID: " & order.SalesOrderID)
        Next
    Catch ex As NotSupportedException
        Console.WriteLine("Exception: " + ex.Message)
    End Try
End Using

Błędy konwersji typów

W języku Visual Basic, gdy właściwość jest mapowana na kolumnę typu bitowego programu SQL Server o wartości 1 przy użyciu CByte funkcji, SqlException jest zgłaszany komunikat "Błąd przepełnienia arytmetycznego". Poniższy przykład wykonuje zapytanie względem Product.MakeFlag kolumny w przykładowej bazie danych AdventureWorks i zgłasza wyjątek, gdy wyniki zapytania są iterowane.

Using context As New AdventureWorksEntities()
    Dim productsList = _
        From product In context.Products _
        Select CByte(product.MakeFlag)

    ' Throws an SqlException exception with a "Arithmetic overflow error 
    ' for data type tinyint" message when a value of 1 is iterated over.
    For Each makeFlag In productsList
        Console.WriteLine(makeFlag)
    Next
End Using

Odwoływanie się do zmiennych nieskalowych nieobsługiwanych

Odwoływanie się do zmiennych innych niż skalarne, takich jak jednostka, w zapytaniu nie jest obsługiwane. Gdy takie zapytanie zostanie wykonane, NotSupportedException zostanie zgłoszony wyjątek z komunikatem "Nie można utworzyć stałej wartości typu EntityType. W tym kontekście są obsługiwane tylko typy pierwotne (takie jak Int32, String i Guid').

Uwaga

Odwoływanie się do kolekcji zmiennych skalarnych jest obsługiwane.

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    Contact contact = context.Contacts.FirstOrDefault();

    // Referencing a non-scalar closure in a query will
    // throw an exception when the query is executed.
    IQueryable<string> contacts = from c in context.Contacts
        where c == contact
        select c.LastName;

    try
    {
        foreach (string name in contacts)
        {
            Console.WriteLine("Name: ", name);
        }
    }
    catch (NotSupportedException ex)
    {
        Console.WriteLine(ex.Message);
    }
}
Using context As New AdventureWorksEntities()

    Dim contact As Contact = context.Contacts.FirstOrDefault()

    ' Referencing a non-scalar closure in a query will
    ' throw an exception when the query is executed.
    Dim contacts = From c In context.Contacts _
                   Where c.Equals(contact) _
                   Select c.LastName

    Try
        For Each name As String In contacts
            Console.WriteLine("Name: ", name)
        Next

    Catch ex As Exception
        Console.WriteLine(ex.Message)
    End Try

End Using

Zapytania zagnieżdżone mogą zakończyć się niepowodzeniem z programem SQL Server 2000

W przypadku programu SQL Server 2000 zapytania LINQ to Entities mogą zakończyć się niepowodzeniem, jeśli generują zagnieżdżone zapytania języka Transact-SQL, które mają co najmniej trzy poziomy głębiej.

Rzutowanie do typu anonimowego

Jeśli zdefiniujesz początkową ścieżkę zapytania, aby uwzględnić powiązane obiekty przy użyciu metody w ObjectQuery<T> obiekcie , a następnie użyjesz Include linQ do projekcji zwracanych obiektów do typu anonimowego, obiekty określone w metodzie include nie zostaną uwzględnione w wynikach zapytania.

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    var resultWithoutRelatedObjects =
        context.Contacts.Include("SalesOrderHeaders").Select(c => new { c }).FirstOrDefault();
    if (resultWithoutRelatedObjects.c.SalesOrderHeaders.Count == 0)
    {
        Console.WriteLine("No orders are included.");
    }
}
Using context As New AdventureWorksEntities()
    Dim resultWithoutRelatedObjects = context.Contacts. _
        Include("SalesOrderHeaders"). _
        Select(Function(c) New With {c}).FirstOrDefault()
    If resultWithoutRelatedObjects.c.SalesOrderHeaders.Count = 0 Then
        Console.WriteLine("No orders are included.")
    End If
End Using

Aby uzyskać powiązane obiekty, nie projektuj zwracanych typów do typu anonimowego.

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    var resultWithRelatedObjects =
        context.Contacts.Include("SalesOrderHeaders").Select(c => c).FirstOrDefault();
    if (resultWithRelatedObjects.SalesOrderHeaders.Count != 0)
    {
        Console.WriteLine("Orders are included.");
    }
}
Using context As New AdventureWorksEntities()
    Dim resultWithRelatedObjects = context.Contacts. _
        Include("SalesOrderHeaders"). _
        Select(Function(c) c).FirstOrDefault()
    If resultWithRelatedObjects.SalesOrderHeaders.Count <> 0 Then
        Console.WriteLine("Orders are included.")
    End If
End Using

Zobacz też