Share via


Problemas conhecidos e considerações no LINQ to Entities

Esta seção fornece informações sobre problemas conhecidos com consultas LINQ to Entities.

Consultas LINQ que não podem ser armazenadas em cache

A partir do .NET Framework 4.5, as consultas LINQ to Entities são automaticamente armazenadas em cache. No entanto, as consultas LINQ to Entities que aplicam o Enumerable.Contains operador a coleções na memória não são armazenadas automaticamente em cache. Também não é permitida parametrizar coleções na memória em consultas LINQ compiladas.

Informações de encomenda perdidas

A projeção de colunas em um tipo anônimo fará com que as informações de ordenação sejam perdidas em algumas consultas executadas em um banco de dados do SQL Server 2005 definido para um nível de compatibilidade de "80". Isso ocorre quando um nome de coluna na lista por ordem corresponde a um nome de coluna no seletor, conforme mostrado no exemplo a seguir:

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

Inteiros não assinados não suportados

Não há suporte para a especificação de um tipo de inteiro não assinado em uma consulta LINQ to Entities porque o Entity Framework não oferece suporte a inteiros não assinados. Se você especificar um inteiro não assinado, uma ArgumentException exceção será lançada durante a tradução da expressão de consulta, conforme mostrado no exemplo a seguir. Este exemplo consulta um pedido com 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

Erros de conversão de tipo

No Visual Basic, quando uma propriedade é mapeada para uma coluna do tipo de bit do SQL Server com um valor de 1 usando a CByte função, um SqlException é lançado com uma mensagem "Erro de estouro aritmético". O exemplo a seguir consulta a Product.MakeFlag coluna no banco de dados de exemplo AdventureWorks e uma exceção é lançada quando os resultados da consulta são iterados.

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

Referenciando variáveis não escalares não suportadas

Não há suporte para a referência a variáveis não escalares, como uma entidade, em uma consulta. Quando essa consulta é executada, uma NotSupportedException exceção é lançada com uma mensagem que afirma "Não é possível criar um valor constante do tipo EntityType. Apenas tipos primitivos ('como Int32, String e Guid') são suportados neste contexto."

Nota

Há suporte para a referência a uma coleção de variáveis escalares.

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

Consultas aninhadas podem falhar com o SQL Server 2000

Com o SQL Server 2000, as consultas LINQ to Entities podem falhar se produzirem consultas Transact-SQL aninhadas com três ou mais níveis de profundidade.

Projetando para um tipo anônimo

Se você definir seu caminho de consulta inicial para incluir objetos relacionados usando o Include método no e, em seguida, usar LINQ ObjectQuery<T> para projetar os objetos retornados para um tipo anônimo, os objetos especificados no método include não serão incluídos nos resultados da consulta.

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

Para obter objetos relacionados, não projete tipos retornados para um tipo anônimo.

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

Consulte também