ith the release of Visual Studio 2008, Microsoft has also updated the VB language to the latest version, 9.0. VB 9.0 boasts several key language enhancements that have been made to support the new Language Integrated Query (LINQ) feature that Microsoft has announced earlier. Part 2 of this series picks up where Part 1 left off, walking you through VB 9.0’s new LINQ support features and providing code examples that illustrate how to use them.
LINQ
One of the key additions to the .NET Framework v3.5 is the support for Language Integrated Query (LINQ). LINQ allows you to manipulate data just like you manipulate database records?using a query language, like SQL. So, whereas before you had to write complex iterative loops to retrieve data, you can now just specify data declaratively using LINQ and the compiler does all the work for you.
LINQ to Objects
LINQ to Objects allows you to use LINQ to query any IEnumerable or IEnumerable(Of t) collections directly. For example, suppose you have a collection of data stored in an array and you want to retrieve a subset of the data quickly. In the old days, you’d write a loop and iteratively retrieve all the data matching your criteria. This is time-consuming because you’d have to write all the logic to perform the comparison, etc. Using LINQ, you can declaratively write the condition using an SQL-like statement and the compiler will do the job for you. Let’s use a real-life example. Suppose you have an array of type String that contains a list of names:
Dim AllNames As String() = _ {"Jeffrey", "Kirby", "Gabriel", "Philip", "Ross", "Adam", _ "Alston", "Warren"}
Now suppose you need to print out all the names in this array that start with the letter “G.” In this case, you can set up a loop and iteratively perform a comparison on each name. Things start to get more complex when you have more complicated filtering rules. Using LINQ, you could specify the filter using the From clause, like this:
Dim FoundNames As IEnumerable(Of String) = _ From Name In AllNames Where Name.StartsWith("G")
When this statement has been executed, FoundNames will now contain a collection of names that starts with the letter “G.” It this case, it returns “Gabriel.” You can now add the names to a ListBox control:
For Each PeopleName In FoundNames ListBox1.Items.Add(PeopleName) Next
You can also use a more complex filter:
Dim FoundNames As IEnumerable(Of String) = _ From Name In AllNames Where Name.StartsWith("G") Or _ Name.Contains("by") Order By Name
In this case, FoundNames will now contain “Gabriel, Kirby.” Note that the result is also sorted. Another useful application of LINQ is to manipulate Windows Forms controls. Suppose you have a large number of controls on your form and you want to uncheck all the CheckBox controls without setting each one individually. You can use the following code with LINQ:
'---retrieve all the checkbox controls in the current form--- Dim checkboxes As IEnumerable = _ From ctrl In Me.Controls Where TypeOf ctrl Is CheckBox For Each c As CheckBox In checkboxes c.Checked = False Next
LINQ to Dataset
Besides manipulating data in memory, you can also use LINQ to query data stored in structures like datasets and datatables. The following example shows how the Authors table within the pubs sample database is loaded onto a Dataset object and then queried using LINQ to Dataset:
Dim conn As SqlConnection Dim comm As SqlCommand Dim adapter As SqlDataAdapter Dim ds As New DataSet '---load the Authors table into the dataset--- conn = New SqlConnection("Data Source=.SQLEXPRESS;" & _ "Initial Catalog=pubs;Integrated Security=True") comm = New SqlCommand("SELECT * FROM Authors", conn) adapter = New SqlDataAdapter(comm) adapter.Fill(ds) '---query for authors living in CA--- Dim authors = From author In ds.Tables(0).AsEnumerable _ Where author.Field(Of String)("State") = "CA" _ Select author
To display the result, you can bind the result to a DataGridView control using the AsDataView() method:
'---bind to a datagridview control--- DataGridView1.DataSource = authors.AsDataView()
Or, you can iteratively loop through the result using a For Each loop:
For Each row As DataRow In authors Console.WriteLine("{0} - {1}, {2}", _ row("au_id"), row("au_fname"), row("au_lname")) Next
If you want to query the authors based on their contract status, use the following query:
Dim authors = From author In ds.Tables(0).AsEnumerable _ Where author.Field(Of Boolean)("Contract") = True _ Select author
The earlier section mentioned the anonymous types feature, new in VB 9.0. Using this feature, you can define a new type without needing to define a new class. To demonstrate a good use of anonymous types, consider the following statement:
'---query for authors living in CA--- Dim authors = From author In ds.Tables(0).AsEnumerable _ Where author.Field(Of String)("State") = "CA" _ Select New With { _ .ID = author.Field(Of String)("au_id"), _ .FirstName = author.Field(Of String)("au_fname"), _ .LastName = author.Field(Of String)("au_lname") _ }
![]() | |
Figure 1. Intellisense Knows: Enter the word “authors” and IntelliSense will return its type. |
Here, you select all the authors living in the state of CA while simultaneously creating a new type consisting of three properties: ID, FirstName, and LastName. Now, type in the word “authors” and IntelliSense will show you that authors is of type EnumerableRowCollection (Of
You can now print out the result using a For Each loop:
For Each auth In authors Console.WriteLine("{0} - {1}, {2}", _ auth.ID, auth.FirstName, auth.LastName) Next
LINQ to SQL
The previous section showed you how to use LINQ to retrieve data from a dataset. A much easier way is to use LINQ to SQL, which allows you to access SQL databases directly.
First, add a new item to your project. Select the Data category and then the LINQ to SQL Classes template. Use DataClasses1.dbml as your default name.
In Server Explorer, establish a connection to the desired database and drag and drop the desired table onto the DataClasses1.dbml page.
Visual Studio 2008 creates a new class called DataClasses1DataContext (which derives from DataContext). This class allows you to programmatically connect to (and access) the authors table. This class is found in the DataClasses1.designer.vb file.
To use LINQ to retrieve the rows in the authors table, first create an instance of the DataClasses1DataContext class:
Dim dataContext As DataClasses1DataContext = _ New DataClasses1DataContext()
Then, use LINQ to select the required rows:
Dim allAuthors = From a In dataContext.authors _ Select a
Finally, print out the individual fields by accessing them directly via the various properties:
For Each a In dataContext.authors Console.WriteLine("{0} - {1}, {2}", _ a.au_id, a.au_fname, a.au_lname) Next
To retrieve all authors living in Utah and then bind the result to a DataGridView control, use the following statements:
Dim dataContext As DataClasses1DataContext = _ New DataClasses1DataContext() Dim allAuthors = From a In dataContext.authors _ Where a.state = "UT" _ Select a '---bind to a datagridview control--- DataGridView1.DataSource = allAuthors
LINQ to XML
Another very cool capability of LINQ is its ability to manipulate XML documents. For example, if you want to create an XML document by hand, you can use the following code snippet in Visual Studio 2008:
Dim library As XElement = _ Professional Windows Vista Gadgets Programming Wrox ASP.NET 2.0 - A Developer's Notebook O'Reilly .NET 2.0 Networking Projects Apress Windows XP Unwired O'Reilly
To save the xml document to file, use the Save() method:
library.Save("Books.xml")
To perform querying on the XML document, load the document from file and then use LINQ to XML:
Dim LibraryBooks As New XDocument LibraryBooks = XDocument.Load("Books.xml") Dim OReillyBooks As IEnumerable = _ From b In LibraryBooks.Descendants("Book") _ Where b.Element("Publisher") = "O'Reilly" _ Select b.Element("Title").Value For Each book In OReillyBooks Console.WriteLine(book) Next
The above code will generate the following output:
ASP.NET 2.0 - A Developer's NotebookWindows XP Unwired
Helpful IntelliSense
The IntelliSense support in Visual Studio 2008 has some additional features that make VB development much more productive and efficient. The following are some of the additions.
Automatic Properties
In Visual Studio 2005, when you type a property statement within a class definition and then press Enter, it automatically created the Get and Set blocks (see Figure 2).
![]() Figure 2. The VS 2005 Method: Typing a property statement within a class definition and then pressing Enter automatically created the Get and Set blocks. | ? | ![]() Figure 3. The VS 2008 Method: Typing the word “prop” and pressing the Tab key twice auto-creates the property definition. |
However, you still needed to fill in the blanks so that the property value can be assigned to an internal private variable, for example.
Conversely, in Visual Studio 2008, this step is done for you automatically. To define a property, all you need to do is to type the word “prop” and then press the Tab key twice in succession (see Figure 3).
![]() Figure 4. View the Connection Details: Change the names in green to what you need. | ? | ![]() Figure 5. Syntax Help: IntelliSense shows the various parameters for those commonly-used constructs. |
Visual Studio 2008 creates the Get and Set blocks, complete with the placeholders for the property name and the internal private variable. All you need to do is to change the name in green to whatever you want and it will update all the other relevant variables (see Figure 4).
More Helpful IntelliSense
IntelliSense is now more helpful with syntax for commonly-used constructs, as Figure 5 shows.
![]() Figure 6. UI Shortcut: IntelliSense hides the list of available options when you push Ctrl. | ? | ![]() Figure 7. The View: The Object Browser shows the list of members in a type. |
Another very useful improvement to IntelliSense is auto-hiding. Figure 6 shows IntelliSense displaying a list of available options. However, many times you would need to refer to the code hidden by the list. In Visual Studio 2008, you can press Ctrl and the list becomes transparent. Once you release Ctrl key, the list comes back on.
Go to Type Definition
In Visual Studio 2005, you can right click on a variable and select Go to Definition to view the declaration for a variable. Visual Studio 2008 goes a step further by allowing you to view the type’s definition. This is very useful, as it brings up the Object Browser and shows you the members of the type (see Figure 7).
One Step Further
I hope that this list of new features in VB 9.0 has helped you to better understand the new power of Visual Basic. Be sure to download the trial edition of Visual Studio 2008 (or download the various free Expression editions) if you have yet to experience the power of all these language extensions.