This blog is targeted at beginning / novice programmers for the Visual Basic (VB) language.

Friday, March 21, 2008

Introduction to LINQ in VB

Overview:

By now, most of us have heard of LINQ and have a general concept of what it is and what can be done with it. For the few that don't I'll lightly skim over it. The remainder of this post will discuss what the major differences are between LINQ in VB and LINQ in C# and also offer some resources to get technical information, practical examples, and some very helpful videos. Best of all; ALL of these resources are FREE!!!

What is LINQ? How do I use it?

"LINQ" is an acronym formed from the .Net 3.5 framework named "Language INtegrated Query". The LINQ framework is composed of LINQ enabled data sources (also commonly referred to as data providers). There is a subset of data providers that are ADO.Net enabled; these are: LINQ To Datasets, LINQ to SQL, and LINQ To Entities (LINQ To Entities is currently in development and has been confirmed to be included in Service Pack 1 update for Visual Studio 2008). There are 2 other included data providers for LINQ called: LINQ To Objects, and LINQ To XML. You can also make your own data providers to be used; there are even data providers already created by 3rd party vendors, such as LINQ To Amazon that you can obtain (some may have associated costs; these are determined by each vendor and are typically not supported by Microsoft).

LINQ is automatically enabled, to some extent, with Visual Studio 2008. Your only real requirement is to use the .Net 3.5 framework. Conceptually you could use Visual Studio 2005 and LINQ; however, there are many additional features/enhancements included with Visual Studio 2008 that can leverage LINQ in a more powerful manner than you would be able to with Visual Studio 2005 (such as Type Inference and XML literals). To use LINQ you simply set your references to the appropriate namespace of the framework class you want to use (VS 2008 includes some namespaces automatically) and then you can use the 'Imports' keyword to enable local declarations at the class level.

Example of enabling at the class level would be:

'System Namespaces
Imports System.Data.Linq

Public Class Form1
'Insert your LINQ code here
End Class

As you can see, enabling LINQ at the class level is quite simple to perform.

What can I do with LINQ?

Well, that is a very broad answer. Basically anything that could be considered a collection or data collection can be used by LINQ. In fact you can even use LINQ for many documents that are created by Office 2007; this is because Office 2007 documents are actually a collection in a zip file of XML and other items. You can actually rename any Word document with a ".zip" extension and then easily view and modify the content within the document. This means you could literally create or modify a Word 2007 document without having Word 2007 installed on the machine!

Why you might ask would someone want to do this? That's quite simple; let's say you have specific information you want to create a set of documents for (similar to using MailMerge in Word); well, if you already have a template or base document created, you could actually use VB to modify the document.xml file within the docx file collection and create the merged document. A great example would be to notify a list of customers that may not have placed an order with your company within the past year. You could use LINQ To SQL (assuming the data is in an SQL database) and iterate through the customer information looking for last activity or order date of more than 1 year ago..take this information and use LINQ To XML to insert the data into your custom created docx file, then save each file created as a new docx filename (such as the customer's account name). Since you don't have to have Word installed to work with an existing docx file, you could leverage the power of your server machine to do the processing work for this task. This means, although not recommended, you could literally create your files right on your SQL Server machine and store the documents within your SQL Server database that could later be used to be sent out to your 'inactive' customers to see if you can drum up some repeat business! How cool is that?!

That's only the tip of the iceberg. Remember, LINQ is designed to easily iterate through a collection of data and to work with that iterations. You can probably already think of a whole bunch of data that it would be great to go through quickly and seamlessly. Because LINQ was designed to use a "standard" query language this means you can create a LINQ query that can be used on SQL, XML, Entities, Objects, and any other data provider you get access to.

This all translates to one wonderful meaning...Once you learn LINQ regardless of the way you use it, you can use LINQ with any other data provider; but, do be aware that there are a few data providers that have a few extended uses that can't be interchanged...but with very little ingenuity you can quickly figure out how to leverage these powerful extensions, such as XML Literals, with the other Data Providers. You can even seamlessly use multiple LINQ query structures within a single query!

What is different in LINQ for VB than in LINQ for C#?

The biggest difference is what is called XML Literals and XML Axis, these can ONLY be used in VB; they are not supported in declarative languages.

First, the big one is XML Literals. With XML Literals you can create XML code that resembles what the output of your XML document will look like. This allows for a true representation of the XML code and document; it's basically the XML WYSIWYG in VB editor! Here's an example of a very simple XML Literal that would have an output that is exactly the same as the code:

Dim myBloxXML = _
           
<Blog>
               
<Name>Visual Basic Helper Blog</Name>
               
<URL>http://visualbasichelper.blogspot.com</URL>
               
<LastPostingName>Introduction to LINQ in VB</LastPostingName>
           
</Blog>

The output would look like this:

<Blog>
     <Name>Visual Basic Helper Blog</Name>
     <URL>http://visualbasichelper.blogspot.com</URL>
     <LastPostingName>Introduction to LINQ in VB</LastPostingName>
</Blog>

As you can see, this is very powerful and allows you to easily determine if something is out of place and how your final document will look like; without ever running the code..and you get the benefits of the type-safety and declaration checking.

But, it doesn't stop there. You can also use embedded expressions; this is both C# and VB enabled. An embedded expression is triggered by using a <%= > enclosure. Here's an example of a simple expression that would retrieve all of the customers from a database table called "Authors". I'm not going to cover the entire method to connect to the database, that'll get covered another time...mainly just look at how I can insert a LINQ query right into my LINQ To XML constructor...and notice that I am mixing the two forms of querying...I'm using LINQ to XML to make the XML tree; but I'm also using LINQ to SQL to get the data to put in the tree...never having to stop my train of thought or change any coding declarations; I just type and go. Here's an example:

Dim myCustXML As XElement = _
           
<Customers>
               
<Customer>
                   
<%= From c In dbcntx.Authors _
                       
Where c.Auth_LName Like "*A*" _
                       
Select _
                       
<Name>
                           
<%= c.Auth_FName %> <%= c.Auth_LName %>
                       
</Name> %>
               
</Customer>
           
</Customers>

The ouput would be:

<Customers>
      <Customer>
            <Name>Stephen Allway</Name>
            <Name>Robert Alonzo</Name>
            <Name>Tom Anand</Name>
            <Name>John Arnold</Name>
            <Name>Alfred Axel</Name>
      </Customer>
</Customers>

As you can see here, I easily went between the two LINQ data providers and formed a very simple tree; I'm only showing a few returned results due to space consumption, but you should get the idea.

This now leaves us with XML Axis; this is basically a shortcut method to tell your code what part of XML to look in. Example would be you could use the trigger "@" to tell your code that you are looking for an XML Attribute. You could use the trigger "..." to tell your code that you are looking for any descendent within the branches of your tree; or you could use "<>.<>" to tell your code where the specific child element is located.

Here are some very quick examples:

'XML calls are based on this XML tree
        Dim myCustomers = _
       
<Customers>
           
<Customer>
               
<Name id="1" age="30">Stephen Allway</Name>
               
<Name id="2" age="55">Robert Alonzo</Name>
               
<Name id="3" age="17">Tom Anand</Name>
               
<Name id="4" age="25">John Arnold</Name>
               
<Name id="5" age="75">Alfred Axel</Name>
           
</Customer>
       
</Customers>

       
'Get age for first name element
        Console.WriteLine("Age: " & myCustomers...<Name>.@<age>)
       
'Get name for first customer by using decendants
        Console.WriteLine("Name: " & myCustomers...<Name>.Value)
       
'Get name for first customer by using child
        Console.WriteLine("Name: " & myCustomers.<Customer>.<Name>.Value)

The entire output would be:

Age: 30
Name: Stephen Allway
Name: Stephen Allway

The other worthwhile note is that the major difference between descendants and child methods is performance. The child method will perform better than the descendants method; this is because the descendants method will search all parts of the element and return ANY and ALL that match it...so if you were to have the following tree:

<Family>
    <Pets>
        <Name>Fluffy</Name>
        <Age>3</Age>
    </Pets>
    <Children>
        <Name>Alexis</Name>
        <Age>10</Age>
    </Children>
</Family>

If you were to use the <Family> as the root node, and call the descendants method looking for <Name> you'd get "Fluffy" and "Alexis" returned; this is because the method only limits it's search to the root node and all child nodes.

If you were to use the same scenario as above and use the child method you could specify if you want to return the Children or Pets node. An example would be:

Console.WriteLine("Name: " & myFamily.<Family>.<Children>.<Name>.Value)

As you can see to call each trigger is simple; these are included with the XML Intellisense by default. All you need to do is to have a variable that is of the XML data type.

Conclusion

This was just an introductory to LINQ in VB; this topic is huge and probably one of the largest (if not the largest) addition to the .Net 3.5 Framework and also for Visual Studio 2008.

As you saw this framework is not limited to Visual Studio 2008; however, if you want to leverage all aspects of LINQ you will have to use Visual Studio 2008 then. You also saw that LINQ was developed to be interchangeable in your code, and there are a few subtle differences between the C# implementation and VB's implementation.

Hopefully, I've been able to get you to a starting point that can the primer for learning more about LINQ. Once you play around with it, you'll probably find yourself constantly finding new ways to use it and it will be one of your most desired tools when working with any sort of data collection.

Additional Resources:

MSDN Language Integrated Query (LINQ) - (http://msdn2.microsoft.com/en-us/library/bb397926.aspx)
The LINQ Project - (http://msdn2.microsoft.com/en-us/netframework/aa904594.aspx)
Beth Massi - Sharing the Goodness that is VB - (http://blogs.msdn.com/bethmassi/)
LINQ 'How Do I' Videos - (http://msdn2.microsoft.com/en-us/vbasic/bb466226.aspx?wt.slv=topsectionsee#linq)

Until next time...Happy Coding!

Tuesday, March 11, 2008

Processing a string into groups of 3

Today, I was browsing the vb.general.discussion newsgroup and came across a person who had wanted to take a textbox input and group the text into groups of 3 using a space to separate the groups. Example being:

Input: 1234567

Output: 1 234 567

Because I was unsure if they were dealing strictly with numbers I found the easiest method was to use the System.String namespace and create a function that would take the input and figure out the total number of groups within the input. It would then separate the groups into a group of 3 and while doing so insert a blank space between each group.

I thought those of you that are new to VB and, especially, new to the System.String namespace may want to see the power that is literally at your fingertips!

This example I had made within about 30 minutes; and was all made on the fly (I know, I know..I didn't plan it out; I was a bad programmer!...shhhh...don't tell anyone!). This is the 'complete' coding:

Setup: I had created a visual basic windows form. I inserted the following controls (left everything at the default settings/names):

2 x Buttons
2 x Labels
2 x Textboxes

Here's the coding I used:

Imports System.String

Public Class Form1
   
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
       
Application.Exit()
   
End Sub

   
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
       
Dim strNewText As String

       
'Call custom function
        strNewText = Create3by3(TextBox1.Text.ToString)

       
'Assign results to textbox
        TextBox2.Text = strNewText
   
End Sub

   
Private Function Create3by3(ByVal strToProcess As String) As String
       
'Declare local variables
        Dim intLength, intNumGroups, intPosition As Short
       
Dim strTemp As String = ""
       
Dim intCount As Integer = 0

       
'Test if value is being passed, if not then notify end-user
        If strToProcess.Length = 0 Then
           
MessageBox.Show("Please enter a value to be processed before continuing.", _
                            "Missing value"
, MessageBoxButtons.OK, MessageBoxIcon.Stop)
           
TextBox1.Focus()
       
End If

       
'Set empty string; avoids warning message of variable not being assigned
        Create3by3 = ""
       
Try
           
'Check if value being passed is more than 3; if not then don't need
            'to go through complexity of processing the string
            If strToProcess.Length <= 3 Then
               
Create3by3 = strToProcess
               
Exit Function
           
End If

           
'Get total length we are working with
            intLength = strToProcess.Length

           
'Important to use the \ NOT the /; because we only want to deal with 
            'whole numbers, no decimals!
            intNumGroups = (intLength \ 3)

           
'This is used to determine the index position of the string we are
            'working with.
            intPosition = intLength - (intNumGroups * 3)

           
'This is a late declaration because it is dependant on how many
            'items we will want in our array which is how many groups we are
            'working with total (our division results + 1 for odd number of
            'the last group (first part of the string)
            Dim sSubStr(intNumGroups + 1) As String

           
'First we insert the odd number of characters; we start at index
            'position 0 and only move until we reach our first group
            sSubStr(intCount) = strToProcess.Substring(0, intPosition) + " "
           
'Don't forget to increase our array index since we filled our first
            'item in the array
            intCount += 1
           
'Now we just loop through the groups and add each one to the array
            For i = 0 To intNumGroups - 1
               
sSubStr(intCount) = strToProcess.Substring(intPosition, 3) + " "
               
'We increase the index position of the string by 3 since we are
                'working with a group of 3
                intPosition += 3
               
'We increase our array index to move to the next item in the array.
                intCount += 1
           
Next
           
'Now we simply just add the entire array into 1 large string
            'with our spaces we placed during our processing
            Create3by3 = String.Concat(sSubStr)
           
'Now we just remove the final spacing; because we don't need it and
            'we have the opportunity to do it now, instead of later.
            Create3by3 = Create3by3.TrimEnd(" ".ToCharArray)
       
Catch ex As Exception
           
'Catch any exceptions; biggest worry is the DivideByZero; but, we are
            'already testing for that at the beginning of this function
            MessageBox.Show("An exception was encountered." & vbCrLf & ex.Message)
       
End Try
       
'Return the results of our processed string!
        Return Create3by3
   
End Function
End Class

As you can see; this is actually not all the difficult of a task and most of the complex parts are already built into Visual Basic. How cool is that? All I needed to do was the split the string, keep track of how many groups there were; then just a matter of building a new string based on this information.

If you or anyone else has a question about this please do not hesitate to post a comment; I'd be happy to clarify it further!

Until next time....Happy Coding!!!