Condividi tramite


Problemi noti e considerazioni in LINQ to Entities

In questa sezione vengono fornite informazioni sui problemi noti relativi alle query LINQ to Entities.

Query LINQ che non possono essere memorizzate nella cache

A partire da .NET Framework 4.5, le query LINQ to Entities vengono memorizzate automaticamente nella cache. Tuttavia, le query LINQ to Entities che applicano l'operatore Enumerable.Contains alle raccolte in memoria non vengono memorizzate automaticamente nella cache. Non è consentita anche la parametrizzazione delle raccolte in memoria nelle query LINQ compilate.

Ordinamento delle informazioni perse

Proiettando colonne in un tipo anonimo, le informazioni di ordinamento andranno perse in alcune query eseguite su un database di SQL Server 2005 impostato su un livello di compatibilità "80". Ciò si verifica quando un nome di colonna nell'elenco order-by corrisponde a un nome di colonna nel selettore, come illustrato nell'esempio seguente:

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

Numeri interi senza segno non supportati

La specifica di un numero intero senza segno in una query LINQ to Entities non è consentita perché l'Entity Framework non supporta i numeri interi senza segno. Se si specifica un intero senza segno, verrà generata un'eccezione ArgumentException durante la conversione dell'espressione di query, come illustrato nell'esempio seguente. Questo esempio esegue una query per un ordine con 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: {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

Errori di conversione dei tipi

In Visual Basic, quando una proprietà viene mappata a una colonna di tipo bit di SQL Server con un valore pari a 1 usando la funzione CByte, viene generata una SqlException con un messaggio di errore di overflow aritmetico. Nell'esempio seguente viene eseguita una query sulla colonna Product.MakeFlag nel database di esempio AdventureWorks e viene generata un'eccezione quando i risultati della query vengono iterati.

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

Riferimento a variabili non scalari non supportate

Il riferimento a variabili non scalari, ad esempio un'entità, in una query non è supportato. Quando viene eseguita una query di questo tipo, viene generata un'eccezione NotSupportedException con un messaggio che indica che "Impossibile creare un valore costante di tipo EntityType. In questo contesto sono supportati solo i tipi primitivi ( ad esempio Int32, String e Guid').

Nota

È supportato il riferimento a una raccolta di variabili scalari.

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: ");
        }
    }
    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

Le query annidate potrebbero non riuscire con SQL Server 2000

Con SQL Server 2000, le query LINQ to Entities potrebbero non riuscire se producono query annidate Transact-SQL di tre o più livelli di profondità.

Proiezione verso un tipo anonimo

Se si definisce il percorso di query iniziale per includere oggetti correlati usando il metodo Include nella ObjectQuery<T> e quindi si usa LINQ per proiettare gli oggetti restituiti in un tipo anonimo, gli oggetti specificati nel metodo include non vengono inclusi nei risultati della query.

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

Per ottenere oggetti correlati, non proiettare i tipi restituiti a un tipo anonimo.

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

Vedere anche