VS 2010 Related Posts

Replace Foreach with LINQ

One of the best ways to start Thinqing in LINQ is to find places where you can replace iterative loops with LINQ queries. This won’t necessarily make your applications any faster at the moment, but by taking advantage of the declarative syntax, it will allow you to change your underlying implementation (ie. parallelize it with PLINQ) easier in the future. Recently, I came across some code that mimicked creating a control array as we used to have in VB6 by iterating over a list of fields and adding controls to a form adding the index to the end of the field name. As the fields are being added,we hook up event listeners along the way. Here’s the old code:


Dim Fields() As String = {"a", "one", "and", "a", "two"}

Dim index As Integer

For Each item As String In Fields
    Dim box As New TextBox
    With box
        .Name = item + index.ToString
        .Top = index * 30
        .Height = 24
        AddHandler .TextChanged, AddressOf OnValueChanged
    End With
    Controls.Add(box)
    index += 1
Next
To break this down, we're creating an index so that we won't have any repeats. We then iterate over our list of fields and create (Project) new textboxes for each of the items in our list. Once we create that value, we then add the handler. Finally we add this item to another list. If we think about this in a set based manner rather than iterative, we can start getting a grasp of what LINQ really has to offer. Let's rewrite this in LINQ starting with our source:

Dim Fields() As String = {"a", "one", "and", "a", "two"}
Dim b1 = From item In Fields
         Select New TextBox With
         {
             .Name = item,
             .Top = 30,
             .Height = 24
         }

Controls.AddRange(boxes)

In this example, we take our starting list. Project (Select) new objects from these values and then pass this list directly into the Controls collection using AddRange. No more For Each.

This is a start, but there's an issue. We need to be able to add the index to this set based operation. One of the little secrets in the LINQ operators is that there are overloads which expose the index. In VB, you can't access these using the LINQ query comprehensions. You have to use the extension methods and Lambda Functions directly as follows:


Dim Fields() As String = {"a", "one", "and", "a", "two"}
Dim boxes = Fields _
            .Select(Function(item, index) _
                New TextBox With {
                    .Name = item + index.ToString(),
                    .Top = index * 30,
                    .Height = 24})

Controls.AddRange(boxes.OfType(Of Control).ToArray)

We're almost there. We just need to add our handlers for each of our new text boxes. While we could call ForEach over an array, it would cause us to iterate over our field list twice (creating two sets of text boxes). We need a way to only iterate over it once. Here, we need to create a new method and using C# iterators. It will take an IEnumerable and return an IEnumerable. By using Yield, it will not cause the enumeration to happen multiple times, but rather to add a new step as each value is being pulled through the enumeration pipeline.


public static class Extensions
    {
       public static IEnumerable<T> WhileEnumerating<T>(this IEnumerable<T> source, Action<T> action)
       {
           foreach (T item in source)
           {
               action(item);
               yield return item;
           }
       }
    }

Now, we can inject methods into the pipeline as follows:


Dim boxes = Fields _
            .Select(Function(item, index) _
                New TextBox With {
                    .Name = item + index.ToString(),
                    .Top = index * 30,
                    .Height = 24}) _
            .WhileEnumerating(Sub(item) AddHandler item.TextChanged, AddressOf OnValueChanged)

Controls.AddRange(boxes.OfType(Of Control).ToArray)

If we wanted to inject more functions, we would just add more .WhileEnumerating methods. Make sure however that each of these methods do not have side effects on other methods of the set. There you have it. Go search for those For Each (foreach) loops in your code and see how you can clean them up with LINQ to Objects.

Posted on 1/16/2010 12:38:00 PM - Comments(0)
Categories: C# LINQ VB VS 2010

LINQ to CSV using DynamicObject and TextFieldParser

In the first post of this series, we parsed our CSV file by simply splitting each line on a comma. While this works for simple files, it becomes problematic when consuming CSV files where individual fields also contains commas. Consider the following sample input:

CustomerID,COMPANYNAME,Contact Name,CONTACT_TITLE
ALFKI,Alfreds Futterkiste,Maria Anders,"Sales Representative"
ANATR,Ana Trujillo Emparedados y helados,Ana Trujillo,"Owner, Operator"
ANTON,Antonio Moreno Taqueria,Antonio Moreno,"Owner"

Typically when a field in a CSV file includes a comma, the field is quote escaped to designate that the comma is part of the field and not a delimiter. In the previous versions of this parser, we didn’t handle these cases. As a result the following unit test would fail given this sample data:


    <TestMethod()>
    Public Sub TestCommaEscaping()
        Dim data = New DynamicCsvEnumerator("C:\temp\Customers.csv")
        Dim query = From c In data
                    Where c.ContactTitle.Contains(",")
                    Select c.ContactTitle

        Assert.AreEqual(1, query.Count)
        Assert.AreEqual("Owner, Operator", query.First)
    End Sub

We could add code to handle the various escaping scenarios here. However, as Jonathan pointed out in his comment to my first post there are already methods that can do CSV parsing in the .Net framework. One of the most flexible ones is the TextFieldParser in the Microsoft.VisualBasic.FileIO namespace. If you code in C# instead of VB, you can simply add a reference to this namespace and access the power from your language of choice.

Retrofiting our existing implementation to use the TextFieldParser is fairly simple. We begin by changing the _FileStream object to being a TextFieldParser rather than a FileStream. We keep this as a class level field in order to stream through our data as we iterate over the rows.

In the GetEnumerator we then instantiate our TextFieldParser and set the delimiter information. Once that is configured, we get the array of header field names by calling the ReadFields method.


    Public Function GetEnumerator() As IEnumerator(Of Object) _
        Implements IEnumerable(Of Object).GetEnumerator

        _FileStream = New Microsoft.VisualBasic.FileIO.TextFieldParser(_filename)
        _FileStream.Delimiters = {","}
        _FileStream.HasFieldsEnclosedInQuotes = True
        _FileStream.TextFieldType = FileIO.FieldType.Delimited

        Dim fields = _FileStream.ReadFields
        _FieldNames = New Dictionary(Of String, Integer)
        For i = 0 To fields.Length - 1
            _FieldNames.Add(GetSafeFieldName(fields(i)), i)
        Next
        _CurrentRow = New DynamicCsv(_FileStream.ReadFields, _FieldNames)

        Return Me
    End Function

    Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
        Dim line = _FileStream.ReadFields
        If line IsNot Nothing AndAlso line.Length > 0 Then
            _CurrentRow = New DynamicCsv(line, _FieldNames)
            Return True
        Else
            Return False
        End If
    End Function

While we are at it, we also change our MoveNext method to call ReadFields to get the parsed string array of the parsed values in the next line. If this is the last line, the array is empty and we return false in the MoveNext to stop the enumeration. We had to make one other change here because in the old version, we passed the full unparsed line in the constructor of the DynamicCsv type and did the parsing there. Since our TextFieldParser will handle that for use, we’ll add an overloaded constructor to our DynamicCsv DynamicObject accepting the pre parsed string array:


Public Class DynamicCsv
    Inherits DynamicObject

    Private _fieldIndex As Dictionary(Of String, Integer)
    Private _RowValues() As String

    Friend Sub New(ByVal values As String(),
                   ByVal fieldIndex As Dictionary(Of String, Integer))
        _RowValues = values
        _fieldIndex = fieldIndex
    End Sub

With these changes, now we can run our starting unit test including the comma in the Contact Title of the second record and it now passes.

If you like this solution, feel free to download the completed Dynamic CSV Enumerator library and kick the tires a bit. There is no warrantee expressed or implied, but please let me know if you find it helpful and any changes you would recommend.

Posted on 12/1/2009 3:31:00 PM - Comments(0)
Categories: Dynamic LINQ VB VB Dev Center VS 2010

LINQ to CSV using DynamicObject Part 2

In the last post, I showed how to use DynamicObject to make consuming CSV files easier. In that example, we showed how we can access CSV columns using the standard dot (.) notation that we use on other objects. Using DynamicObject, we can refer to item.CompanyName and item.Contact_Name rather than item(0) and item(1).

While I’m happy about the new syntax, I’m not content with replacing spaces with underscores as that doesn’t agree with the coding guidelines of using Pascal casing for properties. Because we have control on how the accessors work, we can modify the convention. Let’s reconsider the CSV file that we’re working with. Here’s the beginning:

CustomerID,COMPANYNAME,Contact Name,CONTACT_TITLE,Address,City,Region,PostalCode,Country,Phone,Fax
ALFKI,Alfreds Futterkiste,Maria Anders,Sales Representative,Obere Str. 57,Berlin,NULL,12209,Germany,030-0074321,030-0076545
ANATR,Ana Trujillo Emparedados y helados,Ana Trujillo,Owner,Avda. de la Constituci¢n 2222,Mexico D.F.,NULL,5021,Mexico,(5) 555-4729,(5) 555-3745
ANTON,Antonio Moreno Taqueria,Antonio Moreno,Owner,Mataderos  2312,Mexico D.F.,NULL,5023,Mexico,(5) 555-3932,NULL

Notice here that the header row contains values with a mix of mixed case, all upper, words with spaces, and underscores. To standardize this, we could parse the header and force an upper case at the beginning of each word. That would take a fair amount of parsing code. As a fan of case insensitive programming languages, I figured that if we just strip the spaces and underscores and work against the strings in a case insensitive manner, I’d be happy. In the end, we’ll be able to consume the above CSV with the following code:


Dim data = New DynamicCsvEnumerator("C:\temp\Customers.csv")
Dim query = From c In data
            Where c.City = "London"
            Order By c.CompanyName
            Select c.ContactName, c.CompanyName, c.ContactTitle

To make this change, we change how we parse the header row and the binder name when fetching properties. In our DynamicCsvEnumerator, we already isolated the parsing of the header with a GetSafeFieldName method. Previously we simply returned the input value replacing a space with an underscore. Extending this is trivial:


    Function GetSafeFieldName(ByVal input As String) As String
        'Return input.Replace(" ", "_")
        Return input.
            Replace(" ", "").
            Replace("_", "").
            ToUpperInvariant()
    End Function

That's it for setting up the header parsing changes. We don't need to worry about spaces in the incoming property accessor because it's not legal to use spaces in a method name. I'll also assume that the programmer won't use underscores in the method names by convention. Thus, the only change we need to make in our property accessor is to uppercase the incoming field name to handle the case insensitivity feature. Here's the revised TryGetMember implementation.


    Public Overrides Function TryGetMember(ByVal binder As GetMemberBinder,
                                           ByRef result As Object) As Boolean
        Dim fieldName = binder.Name.ToUpperInvariant()
        If _fieldIndex.ContainsKey(fieldName) Then
            result = _RowValues(_fieldIndex(fieldName))
            Return True
        End If
        Return False
    End Function

All we do is force the field name to upper case and then we can look it up in the dictionary of field indexes that we setup last time. Simple yet effective.

Posted on 12/1/2009 2:07:00 PM - Comments(0)
Categories: LINQ VB Dev Center VS 2010 Dynamic

Pin DataTips in Visual Studio 2010

While debugging in Visual Studio 2010, I noticed that the DataTip now has a new feature. At the right hand side of the variable window, there is now a pin icon.

image

Clicking on this pin icon adds the DataTip to the code window allowing it to float over the existing text.

image

In addition to allowing you to drill into the variable’s values as you would in the watch, locals, or autos windows, You can also add comments which remain with the pinned DataTip.

image

When you stop debugging, the DataTip will disappear. However when you debug into this method again, it will re-appear as long as it is pinned. As a bonus, it will persist even after closing and re-opening Visual Studio.

While Visual Studio 2010 definitely has some rough edges, I continue to be amazed by some of the new UX features that the next version will bring.

Posted on 11/10/2009 10:00:00 PM - Comments(1)
Categories: VS 2010 VB Dev Center

Win 7 with Visual Studio 2010

I’ve been running Windows 7 since the initial public betas (February 2009) and have loved it. One of my favorite features is the ability to drag an application to the left or right side of the monitor and have it snap  to take up half the screen. Even better is using the Windows – Left Arrow and Windows – Right Arrow key combinations to dock the screens without using the mouse. This even works across multiple monitors. It’s a great addition for comparing documents, or in my case when translating code between C# and VB.

By chance, I was playing with Visual Studio Beta 2 tonight when I slipped while dragging a code window. I intended to do a split screen inside of Visual Studio 2010. Instead, I drug the window outside of Visual Studio. To my surprise, the window moved correctly. Pressing my luck, I pressed Windows-Left Arrow and I was amazed that I now had half of the screen with the newly moved code window and the left half with the rest of visual studio.

Here’s a sample screen shot demonstrating the result. In this case, the PostController from this site is in the left half and the ShowPosts view is on the right half.

image

I loved that Win 7 docking supported separate apps, but had no idea that the docking would work with parts of the same app. I have a feeling I’ll be using this feature often! Have you discovered other Win 7 secrets with Visual Studio, I’d love to hear them.

Posted on 10/22/2009 10:07:00 PM - Comments(0)
Categories: VS 2010

LINQ to Entity Visualizer

When demonstrating the LINQ tools, I typically start out showing the LINQ to SQL visualizer that’s available with the C# Samples. Today I saw that Raja Venkatesh has released a Visualizer for ObjectQuery<T> (aka. LINQ to Entities). As you do with the other visualizers, you enable this by simply saving the AnySourceEntityQueryVisualizer.dll to your Visualizers directory. )Note: :the download page specifies to copy it to your C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Packages\Debugger\Visualizers. However, Windows 7 blocks saving files there by default. Alternatively, you can copy it to your My Documents\Visual Studio 2008\Visualizers.

Once you install it, put a breakpoint after your query is declared. If you hover over the query variable, you should see the magnifying glass indicating the debugger visualizer:

image

Clicking on the magnifying glass brings you to a screen that shows the Expression, projected SQL, and Connection properties. If you click “Execute”, you will see the server log and a grid with the results.

image

If you want to try it out, feel free to download it from the Visual Studio Gallery page for the LINQ to Entity Visualizer. I’ll be adding a linq to this on my LINQ Tool list as well.

Posted on 9/10/2009 9:03:00 PM - Comments(4)
Categories: Entity Framework VS 2008 VS 2010

LINQ to SQL DataLoadOptions.LoadWith and Take

While trying to increase the performance of this site, I found a bug which may drastically slow the performance. By default when navigating to child objects from a parent object, LINQ to SQL lazy loads the children. This is good when you don't know if you want the children.

However, on this site when viewing posts, I ALWAYS display the categories and number of comments. As mentioned in LINQ in Action, you can eager load child records using the context's LoadOptions to set the child to be eagerly loaded with the parent using the following:


Dim dc As New LinqBlogDataContext
Dim options As New DataLoadOptions
options.LoadWith(Function(p As PostItem) p.CategoryPosts)
options.LoadWith(Function(cp As CategoryPost) cp.Category)
options.LoadWith(Function(p As PostItem) p.Comments)
dc.LoadOptions = options

There are a couple issues with the implementation at this point however. First, the LoadWith setting only works for one level of hierarchy. It does not automatically navigate to grandchildren records. In this case, you may need to project into an anonymous type to remove that extra level of the object graph.

The trickier situation comes when trying to do paging over the result sets. When traversing one level, the LoadOptions work fine for standard queries, however as soon as you throw a Take clause in, the LoadWith options are ignored as shown below:


Dim good =  From p In dc.PostItems _
            Order By p.PubDate Descending _
            Select p

Dim bad =   From p In dc.PostItems _
            Order By p.PubDate Descending _
            Take 5
            Select p

In the first case, a single query is sent to the database when navigating to the children. In the second (bad) query, separate statements are sent to the database as we fetch the children. I submitted a bug item on this. The solution here (if you target the 4.0 framework) is to include a Skip(0) clause which will cause the Take to not short circuit the LoadOptions:


Dim fixed = From p In dc.PostItems _
            Order By p.PubDate Descending _
            Skip 0
            Take 5
            Select p

Unfortunately, this trick doesn't work with the current VS 2010 build when targeting 3.5. I suspect that you may need to target 4.0 in order to get Take to play nice with the LoadOptions.

Posted on 7/15/2009 11:58:00 AM - Comments(0)
Categories: VS 2010 LINQ

Disable Historical Debugger when using MVC with VS 2010 beta1

I've had a bit of down time between contracts recently and have been taking the opportunity to learn some technologies that I haven't had time to get into before. Since I've read so much about it, I thought I would try out ASP.Net MVC. Since it was just for fun, I figured I'd bite the bullet and try it under VS 2010.

I build a small sample following the tutorials at http://www.asp.net/learn/mvc/, however when I try to run it in VS 2010, the app crashes on me. There's enough "Magic" going on inside MVC, including the routing engine and dynamic loading of the controllers and views that trying to debug MVC is challenging enough when the IDE behaves. When it doesn't it makes life significantly more problematic. Naturally VS hard crashes rather than breaking in my code to let me figure out what's going wrong.

It turns out there wasn't a problem in my code, but rather an issue with MVC and the Historical Debugger which is turned on by default in VS 2010. To fix the issue, open the Option dialog (under Tools - Options) and locate the Historical Debugger tab. Uncheck the "Enable Historic Debugging" option.

Historical Debugging Option Screen

Joe Cartano of the ASP team assures us that this will be fixed in Beta 2, so hopefully this is only a temporary situation. Maybe next time I'll remember to read the release notes completely before banging my head against the wall.

Posted on 7/8/2009 3:06:00 PM - Comments(0)
Categories: VS 2010 MVC

LINQ to SQL designer in VS 2010 Beta 1

There is a bug in the upgrade process when converting a LINQ to SQL designer (.dbml) file from VS 2008 to VS 2010. They changed the implementation to hold the layout information in a .dbml.diagram file rather than the .dbml.layout file. Instead of just renaming the existing file, it replaces it with a new one effectively loosing all of the layout customizations you may have made to the design surface.

Luckily there is an easy fix. Just delete newly created .diagram file and then rename the old .dbml.layout file with a .dbml.diagram extension. If you want to be safe, you can rename the first .diagram file rather than deleting it. When you open your design surface now, your original class layout should be back.

I'm told by the product team that this will be fixed in the next release. That's why it's called a Beta release.

Posted on 6/2/2009 5:22:00 PM - Comments(0)
Categories: VS 2010 LINQ

LINQ to SQL enhancements for 2010

One question that I'm asked repeatedly is, "Is LINQ dead?" The quick answer is, NO. The more appropriate question is "Is LINQ to SQL dead?" That one is a bit trickier, particularly after some of the blog posts from the data programmability team regarding their emphasis moving forward for LINQ to SQL and the Entity Framework.

My take on it is that LINQ to SQL is in a similar situation to Winforms. Both are still supported and have teams dedicated to them, but don't expect much in terms of new features, rather the focus is on bug fixes. The main development focus for new features is placed more on the Entity Framework and similarly WPF. For those who love taking SAT tests, you can think of it as

LINQ to SQL : Entity Framework :: Winforms : WPF

Proof of the point, Damien Guard, one of the people on the LINQ to SQL team, just posted a list of 40+ changes that are coming for LINQ to SQL for .Net 4.0. Looking through the list, most of the items are bug fix items and not feature enhancements. 

Of the list of items, the biggest change I see is specifying the text parameter lengths. Adding this eliminates some of DBA's performance concerns in terms of query plan reuse. This is one area that DBA's have focused on in terms of the performance issue and was an unfortunate oversight in the initial release.

There are a number of larger features that people continue to ask for that are not being included.

  • Support for more complex table to object relationships. This is really the point of the EDM, so I don't see this ever making it into LINQ to SQL.
  • Ability to update a model from database schema changes. Again, the EDMX designer supports this, so I wouldn't hold your breath.
  • No support for SQL 2008's new data types, including the Spatial types, HierarchyId and Filestream. If any of the features were added, I would expect this to be included at some point.

Damien's list should be proof that LINQ to SQL is not dead, but it isn't going to receive significant enhancements that you may want. Check out the 2010 beta and see what changes are there for yourself and give feedback to the teams before it's too late.

Posted on 6/2/2009 9:57:00 AM - Comments(1)
Categories: Entity Framework LINQ VS 2010

PDC Content comes to Atlanta

In case you missed the PDC, don't miss the opportunity to get some of the content for a greatly reduced cost. Microsoft touring the country with their MSDN Developer Conference  and are coming to Atlanta on December 16th at the Westin Peachtree Plaza.

I'll be among the who's who list of local experts presenting the content. For my part, I'll be showing you the language enhancements that are coming for C# 4.0 and VB 10.0. This release is more about parity than ground-breaking advances like we had with LINQ in the last release. There are a number of nice features which should make programming a bit easier.

In addition to the language session, Glen has a full writeup including the speakers and sessions. There's also a number of cool give-aways. Sign-up today for a great event.

Posted on 11/29/2008 4:42:00 PM - Comments(1)
Categories: Code Camp VS 2010