Dela via


Skriv relationer i frågeåtgärder (Visual Basic)

Variabler som används i LINQ-frågeåtgärder (Language-Integrated Query) är starkt skrivna och måste vara kompatibla med varandra. Stark skrivning används i datakällan, i själva frågan och i frågekörningen. Följande bild identifierar termer som används för att beskriva en LINQ-fråga. Mer information om delarna i en fråga finns i Grundläggande frågeåtgärder (Visual Basic).

Screenshot showing a pseudocode query with elements highlighted.

Typen av intervallvariabel i frågan måste vara kompatibel med typen av element i datakällan. Frågevariabelns typ måste vara kompatibel med sekvenselementet som definierats i Select -satsen. Slutligen måste typen av sekvenselement också vara kompatibel med den typ av loopkontrollvariabel som används i -instruktionen For Each som kör frågan. Den här starka skrivningen underlättar identifiering av typfel vid kompileringstillfället.

Visual Basic gör stark inskrivning bekväm genom att implementera slutsatsdragning av lokal typ, även kallat implicit skrivning. Den funktionen används i föregående exempel, och du ser att den används i LINQ-exemplen och dokumentationen. I Visual Basic utförs den lokala typinferensen helt enkelt med hjälp av en Dim instruktion utan en As sats. I följande exempel city skrivs starkt som en sträng.

Dim city = "Seattle"

Kommentar

Den lokala typinferensen fungerar bara när Option Infer är inställt på On. Mer information finns i Infer-instruktion för alternativ.

Men även om du använder lokal typinferens i en fråga finns samma typrelationer bland variablerna i datakällan, frågevariabeln och frågekörningsloopen. Det är användbart att ha en grundläggande förståelse för dessa typrelationer när du skriver LINQ-frågor eller arbetar med exemplen och kodexemplen i dokumentationen.

Du kan behöva ange en explicit typ för en intervallvariabel som inte matchar den typ som returneras från datakällan. Du kan ange typen av intervallvariabel med hjälp av en As sats. Detta resulterar dock i ett fel om konverteringen är en begränsad konvertering och Option Strict är inställd på On. Därför rekommenderar vi att du utför konverteringen på de värden som hämtas från datakällan. Du kan konvertera värdena från datakällan till den explicita intervallvariabeltypen med hjälp Cast av metoden . Du kan också omvandla de värden som valts i Select -satsen till en explicit typ som skiljer sig från typen av intervallvariabel. Dessa punkter illustreras i följande kod.

Dim numbers1() As Integer = {1, 2, 4, 16, 32, 64}
Dim numbers2() As Double = {5.0#, 10.0#, 15.0#}

' This code does not result in an error.
Dim numberQuery1 = From n As Integer In numbers1 Where n > 5

' This code results in an error with Option Strict set to On. The type Double
' cannot be implicitly cast as type Integer.
Dim numberQuery2 = From n As Integer In numbers2 Where n > 5

' This code casts the values in the data source to type Integer. The type of
' the range variable is Integer.
Dim numberQuery3 = From n In numbers2.Cast(Of Integer)() Where n > 5

' This code returns the value of the range variable converted to Integer. The type of
' the range variable is Double.
Dim numberQuery4 = From n In numbers2 Where n > 5 Select CInt(n)

Frågor som returnerar hela element i källdata

I följande exempel visas en LINQ-frågeåtgärd som returnerar en sekvens med element som valts från källdata. Källan, names, innehåller en matris med strängar, och frågeutdata är en sekvens som innehåller strängar som börjar med bokstaven M.

Dim names = {"John", "Rick", "Maggie", "Mary"}
Dim mNames = From name In names
             Where name.IndexOf("M") = 0
             Select name

For Each nm In mNames
    Console.WriteLine(nm)
Next

Detta motsvarar följande kod, men är mycket kortare och enklare att skriva. Beroendet av lokal typinferens i frågor är det föredragna formatet i Visual Basic.

Dim names2 = {"John", "Rick", "Maggie", "Mary"}
Dim mNames2 As IEnumerable(Of String) =
    From name As String In names
    Where name.IndexOf("M") = 0
    Select name

For Each nm As String In mNames
    Console.WriteLine(nm)
Next

Följande relationer finns i båda de tidigare kodexemplen, oavsett om typerna bestäms implicit eller explicit.

  1. Typen av element i datakällan, names, är typen av intervallvariabel, name, i frågan.

  2. Typen av objekt som har valts, name, avgör typen av frågevariabel, mNames. Här name är en sträng, så frågevariabeln är IEnumerable(Of String) i Visual Basic.

  3. Frågan som definierats i mNames körs i loopen For Each . Loopen itererar över resultatet av att köra frågan. Eftersom mNames, när den körs, returnerar en sekvens med strängar, är loop-iterationsvariabeln, nm, också en sträng.

Frågor som returnerar ett fält från valda element

I följande exempel visas en LINQ-till SQL-frågeåtgärd som returnerar en sekvens som bara innehåller en del av varje element som valts från datakällan. Frågan tar en samling Customer objekt som datakälla och projicerar endast Name egenskapen i resultatet. Eftersom kundnamnet är en sträng genererar frågan en sekvens med strängar som utdata.

' Method GetTable returns a table of Customer objects.
Dim customers = db.GetTable(Of Customer)()
Dim custNames = From cust In customers
                Where cust.City = "London"
                Select cust.Name

For Each custName In custNames
    Console.WriteLine(custName)
Next

Relationerna mellan variablerna liknar dem i det enklare exemplet.

  1. Typen av element i datakällan, customers, är typen av intervallvariabel, cust, i frågan. I det här exemplet är Customerden typen .

  2. - Select instruktionen returnerar egenskapen för Name varje Customer objekt i stället för hela objektet. Eftersom Name är en sträng blir frågevariabeln, custNames, återigen IEnumerable(Of String), inte för Customer.

  3. Eftersom custNames representerar en sekvens med strängar måste loopens For Each iterationsvariabel, custName, vara en sträng.

Utan lokal typinferens skulle det föregående exemplet vara mer besvärligt att skriva och förstå, vilket visas i följande exempel.

' Method GetTable returns a table of Customer objects.
 Dim customers As Table(Of Customer) = db.GetTable(Of Customer)()
 Dim custNames As IEnumerable(Of String) =
     From cust As Customer In customers
     Where cust.City = "London"
     Select cust.Name

 For Each custName As String In custNames
     Console.WriteLine(custName)
 Next

Frågor som kräver anonyma typer

I följande exempel visas en mer komplex situation. I föregående exempel var det obekvämt att uttryckligen ange typer för alla variabler. I det här exemplet är det omöjligt. I stället för att välja hela Customer element från datakällan, eller ett enda fält från varje element, returnerar satsen i den Select här frågan två egenskaper för det ursprungliga Customer objektet: Name och City. Som svar på Select -satsen definierar kompilatorn en anonym typ som innehåller dessa två egenskaper. Resultatet av körningen nameCityQuery i loopen For Each är en samling instanser av den nya anonyma typen. Eftersom den anonyma typen inte har något användbart namn kan du inte ange typen av nameCityQuery eller custInfo explicit. Med en anonym typ har du alltså inget typnamn att använda i stället för String i IEnumerable(Of String). Mer information finns i Anonyma typer.

' Method GetTable returns a table of Customer objects.
Dim customers = db.GetTable(Of Customer)()
Dim nameCityQuery = From cust In customers
                    Where cust.City = "London"
                    Select cust.Name, cust.City

For Each custInfo In nameCityQuery
    Console.WriteLine(custInfo.Name)
Next

Även om det inte går att ange typer för alla variabler i föregående exempel förblir relationerna desamma.

  1. Typen av element i datakällan är återigen typen av intervallvariabel i frågan. I det här exemplet cust är en instans av Customer.

  2. Eftersom -instruktionen Select genererar en anonym typ måste frågevariabeln, nameCityQuery, implicit skrivas som en anonym typ. En anonym typ har inget användbart namn och kan därför inte anges explicit.

  3. Typen av iterationsvariabel i loopen For Each är den anonyma typ som skapades i steg 2. Eftersom typen inte har något användbart namn måste typen av loop-iterationsvariabel fastställas implicit.

Se även