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).
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.
Typen av element i datakällan,
names
, är typen av intervallvariabel,name
, i frågan.Typen av objekt som har valts,
name
, avgör typen av frågevariabel,mNames
. Härname
är en sträng, så frågevariabeln är IEnumerable(Of String) i Visual Basic.Frågan som definierats i
mNames
körs i loopenFor Each
. Loopen itererar över resultatet av att köra frågan. EftersommNames
, 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.
Typen av element i datakällan,
customers
, är typen av intervallvariabel,cust
, i frågan. I det här exemplet ärCustomer
den typen .-
Select
instruktionen returnerar egenskapen förName
varjeCustomer
objekt i stället för hela objektet. EftersomName
är en sträng blir frågevariabeln,custNames
, återigen IEnumerable(Of String), inte förCustomer
.Eftersom
custNames
representerar en sekvens med strängar måste loopensFor 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.
Typen av element i datakällan är återigen typen av intervallvariabel i frågan. I det här exemplet
cust
är en instans avCustomer
.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.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.