Dela via


Kända problem och överväganden i LINQ till entiteter

Det här avsnittet innehåller information om kända problem med LINQ till entitetsfrågor.

LINQ-frågor som inte kan cachelagras

Från och med .NET Framework 4.5 cachelagras LINQ till entitetsfrågor automatiskt. LINQ till entitetsfrågor som tillämpar operatorn Enumerable.Contains på minnesinterna samlingar cachelagras dock inte automatiskt. Det är inte heller tillåtet att parametrisera minnesinterna samlingar i kompilerade LINQ-frågor.

Orderinformation har förlorats

Om du projicerar kolumner i en anonym typ går beställningsinformationen förlorad i vissa frågor som körs mot en SQL Server 2005-databas som är inställd på en kompatibilitetsnivå på "80". Detta inträffar när ett kolumnnamn i order-by-listan matchar ett kolumnnamn i väljaren, som du ser i följande exempel:

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

Osignerade heltal stöds inte

Det går inte att ange en osignerad heltalstyp i en LINQ-till-entitetsfråga eftersom Entity Framework inte stöder osignerade heltal. Om du anger ett osignerat heltal utlöses ett ArgumentException undantag under översättningen av frågeuttrycket, som du ser i följande exempel. Det här exemplet frågar efter en order med 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

Typkonverteringsfel

När en egenskap mappas till en kolumn av SQL Server-bittyp med värdet 1 med hjälp CByte av funktionen i Visual Basic genereras en SqlException med meddelandet "Aritmetiskt spillfel". I följande exempel efterfrågas Product.MakeFlag kolumnen i AdventureWorks-exempeldatabasen och ett undantag genereras när frågeresultatet itereras över.

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

Refererar till icke-skalära variabler som inte stöds

Det går inte att referera till icke-skalära variabler, till exempel en entitet, i en fråga. När en sådan fråga körs genereras ett NotSupportedException undantag med meddelandet "Det går inte att skapa ett konstant värde av typen EntityType. Endast primitiva typer (till exempel Int32, String och Guid) stöds i det här sammanhanget."

Kommentar

Det finns stöd för att referera till en samling skalärvariabler.

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

Kapslade frågor kan misslyckas med SQL Server 2000

Med SQL Server 2000 kan LINQ till entitetsfrågor misslyckas om de skapar kapslade Transact-SQL-frågor som är tre eller flera nivåer djupa.

Projicera till en anonym typ

Om du definierar din första frågesökväg för att inkludera relaterade objekt med hjälp Include av metoden på ObjectQuery<T> och sedan använder LINQ för att projicera de returnerade objekten till en anonym typ, inkluderas inte de objekt som anges i inkluderingsmetoden i frågeresultatet.

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

Om du vill hämta relaterade objekt ska du inte projicera returnerade typer till en anonym typ.

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

Se även