Známé problémy a aspekty u LINQ to Entities

Tato část obsahuje informace o známých problémech s dotazy LINQ to Entities.

Dotazy LINQ, které nelze uložit do mezipaměti

Počínaje rozhraním .NET Framework 4.5 se dotazy LINQ to Entities automaticky ukládají do mezipaměti. Dotazy LINQ to Entities, které operátor aplikují Enumerable.Contains na kolekce v paměti, se ale automaticky neukládají do mezipaměti. Parametrizace kolekcí v paměti v kompilovaných dotazech LINQ není povolena.

Ztracené informace o objednávce

Promítání sloupců do anonymního typu způsobí ztrátu informací o řazení v některých dotazech, které se spustí v databázi SQL Serveru 2005 nastavené na úroveň kompatibility 80. K tomu dochází v případě, že název sloupce v seznamu pořadí odpovídá názvu sloupce v selektoru, jak je znázorněno v následujícím příkladu:

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

Nepodepsané celá čísla nejsou podporována.

Zadání celočíselného typu bez znaménka v dotazu LINQ to Entities není podporováno, protože Entity Framework nepodporuje celá čísla bez znaménka. Pokud zadáte celé číslo bez znaménka, ArgumentException při překladu výrazu dotazu se vyvolá výjimka, jak je znázorněno v následujícím příkladu. Tento příklad dotazů na objednávku s ID 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

Chyby převodu typů

Pokud je vlastnost v jazyce Visual Basic namapována na sloupec bitového typu SQL Serveru s hodnotou 1 pomocí CByte funkce, SqlException vyvolá se zpráva "Aritmetické přetečení". Následující příklad dotazuje Product.MakeFlag sloupec v ukázkové databázi AdventureWorks a při iterování výsledků dotazu dojde k výjimce.

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

Odkazování na jiné než skalární proměnné se nepodporují

Odkazování na jiné než skalární proměnné, jako je například entita, není v dotazu podporováno. Když se takový dotaz spustí, NotSupportedException vyvolá se výjimka se zprávou, že nelze vytvořit konstantní hodnotu typu EntityType. V tomto kontextu jsou podporovány pouze primitivní typy (například Int32, String a Guid).

Poznámka:

Podporuje se odkazování na kolekci skalárních proměnných.

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

Vnořené dotazy můžou selhat s SQL Serverem 2000

U SQL Serveru 2000 může dotaz LINQ to Entities selhat, pokud vytváří vnořené dotazy Transact-SQL, které jsou tři nebo více úrovní hluboko.

Promítání na anonymní typ

Pokud definujete počáteční cestu dotazu tak, aby zahrnovala související objekty pomocí Include metody na ObjectQuery<T> a pak pomocí LINQ projektovat vrácené objekty na anonymní typ, objekty zadané v metodě include nejsou zahrnuty do výsledků dotazu.

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

Pokud chcete získat související objekty, nevracejte typy do anonymního typu.

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

Viz také