.NET Blog

Tony Cavaliere

 
My Favourite Albums
  And the Grappa wins.
E-mail me Send mail

Disclaimer

Hey unlike other bloggers I stand by what I say but just in case. The opinions expressed herein are my own except on Tuesday when the second card is not turned up otherwise it ain't worth squat.

© Copyright 2013

Linq to SQL: A small CRUD application

For the last month or so I have been helping out with a medium .NET windows forms application that uses Linq to SQL for it’s ORM. It had been a while since I last used Linq to SQL, so I thought it would be a good time to refresh my skills and write a proof of concept application, one that used Linq to SQL to create, read, update and delete records.

The model consists of four classes and is shown in the following figure.

BookModel

Linq to SQL Model Diagram

The Book object contains references to each of the Genre, Publisher and Author objects. In this contrived example, a Book must have one and only one Author, Genre and Publisher.

Early one in this prototype, it became apparent that it was important to manage the lifetime on the Linq to SQL DataContext. Rich Strahl has an excellent post on managing the lifetime of DataContext. In this application, the Linq to SQL DataContext is abstracted within a BookRepository class and a singleton is used to serve up a reference to the repository. The following listing shows how this singleton is implemented.

    8   public sealed class Repository

    9   {

   10 

   11     static BooksRepository _bookRepository = null;

   12     static string connectionString;

   13 

   14     private Repository() { }

   15 

   16     public static void ConnectionString(string cs) { connectionString = cs; }

   17 

   18     public static BooksRepository BookRepository(Boolean create)

   19     {

   20       if (connectionString == null)

   21         throw new ApplicationException("Need to set connection string for Repository");

   22       if (!create && _bookRepository != null) return _bookRepository;

   23       else

   24       {

   25         _bookRepository = new BooksRepository(connectionString);

   26         return _bookRepository;

   27       }

   28     }

   29 

   30   }

The BookRepository method has a single parameter and decides whether to return a new BooksRepository or to return the existing BooksRepository, remember the BooksRepository abstracts the DataContext. Each call to  Repository.BookRepository(false) returns the same BooksRepository and therefore uses same DataContext.

Currently rated 1.5 by 48 people

  • Currently 1.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: LINQ
Posted by CynotWhyNot on Wednesday, July 08, 2009 9:15 AM
Permalink | Comments (95) | Post RSSRSS comment feed

Beth Massi and Scott Hanselman at TVBUG

Last week (May 12, 2008) both Beth Massi and Scott Hanselman presented at the Toronto Visual Basic User Group (TVBUG) and what a treat. Not one, but two expert speakers at a user group meeting. Beth gave a great session on building a data access layer using LINQ to SQL and Scott gave a wonderful presentation on ADO.NET Data Services. I especially enjoyed the tongue in cheek format where both Beth a Scott jokingly commented on each other's presentation. Scott's introduction to himself was hilarious. If you haven't seen it please check out his MIX08 presentation.

Thanks to Rob Windsor for organizing one of the best user group meetings that I have ever attended and believe me I've attended my fair share of meetings.

Standing room only at TVBUG where Beth Massi and Scott Hanselman talk about LINQ to SQL and ADO.NET Data Services.

01 TVBUG

A close up of Bath and Scott presenting at TVBUG.

02 TVBUG

Guess the movie

[Yelling] ... and it was my fault because I knew it was gonna happen. But if a white person sees two black men walking towards her and she turns and walks in the other direction, she's a racist, right?

Currently rated 1.5 by 4 people

  • Currently 1.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by CynotWhyNot on Sunday, May 18, 2008 8:01 AM
Permalink | Comments (40) | Post RSSRSS comment feed

Request.ServerVariables, the LINQ way.

I have been using LINQ for quite some time and have even had a few posts on LINQ. I was first exposed to LINQ at a .NET user group and my initial reaction was WOW now that is cool. Having a common language for querying data from XML, SQL, Oracle, ADO, and in memory objects, now that's the way to do it. There are even LINQ providers for TerraServer, Amazon and Flickr, just too name a few.

Lately as I am coding I always try to think LINQ. It's not easy as most of us are set in our ways. But we must change with the times. So I keep asking myself is there a LINQ way of doing this?

I recently needed access to the  server variables exposed in the Request object. The server variables are stored in a NameValueCollection. Did I hear collection! If it's a collection then there most be a LINQ way handling these server variables.

Unfortunately, the NameValueCollection does not expose the name/value pairs as a collection of a single object but rather it has two collections; one for the keys and the other for the values. This does not lend itself well for use with LINQ. How can we adapt this NameValueCollection to be used within a LINQ query? This is where extensions come to the rescue. I decided to write an extension method ToEnumerable that would take the name/value pairs and package them into a custom type. The extension code is shown in Listing 1.

Listing 1: NameValueExtension

Imports Microsoft.VisualBasic

Imports System.Runtime.CompilerServices

 

Public Module NameValueCollectionExtension

 

    <Extension()> _

    Public Function ToEnumerable(ByVal nvCol As NameValueCollection) _

        As IEnumerable(Of NameValue)

 

        Dim item As NameValue

        Dim listNV As New List(Of NameValue)

        Dim i As Integer

        For i = 0 To nvCol.Count - 1

            item = New NameValue(nvCol.Keys(i), nvCol.Item(nvCol.Keys(i)))

            listNV.Add(item)

        Next

        Return listNV.AsEnumerable

 

    End Function

 

End Module

 

Public Class NameValue

 

    Private _key As String

    Public Property Key() As String

        Get

            Return _key

        End Get

        Set(ByVal value As String)

            _key = value

        End Set

    End Property

 

    Private _Value As String

    Public Property Value() As String

        Get

            Return _Value

        End Get

        Set(ByVal value As String)

            _Value = value

        End Set

    End Property

 

    Public Sub New(ByVal key As String, ByVal val As String)

        Me.Key = key

        Me.Value = val

    End Sub

 

End Class

This listing has a module, NameValueCollectionExtension, and a class, NameValue. The NameValue class has two properties; Key and Value and a constructor used to conveniently instantiate the object. The extension method, ToEnumerable, takes the NameValueCollection and loops through, extracting the key and value. The key and value is used to create an instance of NameValue object and is added to a  List(Of NameValue).

Listing 2 shows how this extension method can be used in the context of Request.ServerVariables.

Listing 2: Using LINQ on Request.ServerVariables

Imports System.Data

Imports NameValueCollectionExtension

 

Partial Class _Default

    Inherits System.Web.UI.Page

 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

 

        GridView1.DataSource = _

            From ServerVariables In Request.ServerVariables.ToEnumerable _

            Where (ServerVariables.Key.Contains("HTTP"))

 

        GridView1.DataBind()

 

    End Sub

 

End Class

This listing does not contain the markup as it only has a GridView. With the addition of this extension method we can now use Request.ServerVariables in a LINQ query. It is relatively simple to filter, order or even join Request.ServerVariables. In the above code listing all server variables where the key has the string HTTP is included. The result is bound to the GridView and is shown in Figure 1.

Figure 1: Request.ServerVariables Bound to GridView

Request

One last point this extension method is not confined to Request.ServerVariables but can be used on any object of type NameValueCollection.

Thanks to Keith J. Farmer's comment on making use of the build-in generic KeyValuePair<TKey,TValue>. The revised extension method is shown below.

Imports Microsoft.VisualBasic

Imports System.Runtime.CompilerServices

 

Public Module NameValueCollectionExtension

 

    <Extension()> _

    Public Function AsEnumerable(ByVal nvCol As NameValueCollection) _

        As IEnumerable(Of KeyValuePair(Of String, String))

 

        Dim lnv As New List(Of KeyValuePair(Of String, String))

        Dim i As Integer

        For i = 0 To nvCol.Count - 1

            lnv.Add(New KeyValuePair(Of String, String) _

                    (nvCol.Keys(i), nvCol.Item(nvCol.Keys(i))))

        Next

        Return lnv.AsEnumerable

 

    End Function

 

End Module

Guess the movie

That really was a Hattori Hanzo sword.

Currently rated 1.5 by 39 people

  • Currently 1.461538/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: ASP.NET | LINQ
Posted by CynotWhyNot on Friday, May 02, 2008 4:11 PM
Permalink | Comments (165) | Post RSSRSS comment feed

LINQ to SQL versus ADO, Let's get ready to rumble.

Language Integrated Query (LINQ) was introduced in VS 2008 and is a great way to query data. It is a standard query syntax that essentially provides a common way of querying data regardless of whether the data source in SQL, XML or in-memory objects.

Prior to .NET 3.5 developers would typically use ADO to query relational databases, specifically, if you were querying SQL Server you would be using the SQL ADO libraries. If you wanted to retrieve the data as quickly as possible then you used DataReaders, but it was the developer's responsibility to maintain the data. If performance was not an issue then developers would typically opt for Datasets, a more feature rich mechanism for retrieving and storing the data.

But how performant (I know it's not a word but ...) is LINQ to SQL? I decided to put it to the test.

I wrote a console application to test the performance of LINQ to SQL, ADO Datasets and ADO DataReaders. The application consists of 3 methods one to run LINQ to SQL, one for Datasets and the last for DataReaders. This code is shown in Listing 1. In order to level the playing field the DataReader method populates a custom object, MyCustomer. The code for this class is also included in the listing. In each case we are querying the customer table (91 rows), 10,000 times.

I am using the northwind database and SQLExpress.

Listing 1:

 

Imports System.Data

Imports System.Data.SqlClient

Imports System.Configuration

 

Module Module1

 

    Sub Main()

 

        Dim start As DateTime

        Dim [end] As DateTime

 

        start = DateTime.Now

        GetUsingLINQ()

        [end] = DateTime.Now

        ElapsedTime(start, [end], "Using LINQ")

 

        start = DateTime.Now

        GetUsingDataset()

        [end] = DateTime.Now

        ElapsedTime(start, [end], "Using ADO Dataset")

 

        start = DateTime.Now

        GetUsingDataReader()

        [end] = DateTime.Now

        ElapsedTime(start, [end], "Using ADO DataReader")

 

        System.Console.ReadLine()

 

    End Sub

 

    Private Sub ElapsedTime(ByVal s As DateTime, ByVal e As DateTime, ByVal msg As String)

        System.Console.WriteLine(msg + ": " + ((e.Ticks - s.Ticks) / 10000000.0).ToString + " secs")

    End Sub

 

    Private Sub GetUsingLINQ()

        Dim db As New NorthwindDataContext()

        Dim query = From c In db.Customers

        Dim i As Integer

        For i = 0 To 10000

            query.ToList()

        Next

    End Sub

 

    Private Sub GetUsingDataset()

 

        Dim cstrcol As ConnectionStringSettingsCollection = ConfigurationManager.ConnectionStrings

        Dim cs As String = cstrcol("LINQ2SQLvsADO.My.MySettings.NorthwindConnectionString").ToString

        Dim cn As New SqlConnection(cs)

 

        Dim query As String = _

            "select [CustomerID], [CompanyName], [ContactName], [ContactTitle], " + _

            "[Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax] " + _

            "from [dbo].[Customers]"

 

        Dim cmd As New SqlCommand(query, cn)

        Dim da As New SqlDataAdapter(cmd)

        Dim ds As New DataSet

 

        Dim i As Integer

        For i = 0 To 10000

            da.Fill(ds)

        Next

 

    End Sub

 

    Private Sub GetUsingDataReader()

 

        Dim cstrcol As ConnectionStringSettingsCollection = ConfigurationManager.ConnectionStrings

        Dim cs As String = cstrcol("LINQ2SQLvsADO.My.MySettings.NorthwindConnectionString").ToString

        Dim cn As New SqlConnection(cs)

 

        Dim query As String = _

            "select [CustomerID], [CompanyName], [ContactName], [ContactTitle], " + _

            "[Address], [City], [Region], [PostalCode], [Country], [Phone], [Fax] " + _

            "from [dbo].[Customers]"

 

        Dim cmd As New SqlCommand(query, cn)

        Dim dr As SqlDataReader

        cn.Open()

 

        Dim mc As New MyCustomer

 

        Dim i As Integer

        For i = 0 To 10000

            dr = cmd.ExecuteReader

            While dr.Read

                mc.CustomerID = dr("CustomerID").ToString

                mc.CompanyName = dr("CompanyName").ToString

                mc.ContactName = dr("ContactName").ToString

                mc.ContactTitle = dr("ContactTitle").ToString

                mc.Address = dr("Address").ToString

                mc.City = dr("City").ToString

                mc.PostalCode = dr("PostalCode").ToString

                mc.Country = dr("Country").ToString

                mc.Phone = dr("Phone").ToString

                mc.Fax = dr("Fax").ToString

                mc.Region = dr("Region").ToString

            End While

            dr.Close()

        Next

 

    End Sub

 

 

End Module

 

Public Class MyCustomer

 

    Private _CustomerID As String

    Public Property CustomerID() As String

        Get

            Return _CustomerID

        End Get

        Set(ByVal value As String)

            _CustomerID = value

        End Set

    End Property

    Private _CompanyName As String

    Public Property CompanyName() As String

        Get

            Return _CompanyName

        End Get

        Set(ByVal value As String)

            _CompanyName = value

        End Set

    End Property

    Private _ContactName As String

    Public Property ContactName() As String

        Get

            Return _ContactName

        End Get

        Set(ByVal value As String)

            _ContactName = value

        End Set

    End Property

    Private _ContactTitle As String

    Public Property ContactTitle() As String

        Get

            Return _ContactTitle

        End Get

        Set(ByVal value As String)

            _ContactTitle = value

        End Set

    End Property

    Private _Address As String

    Public Property Address() As String

        Get

            Return _Address

        End Get

        Set(ByVal value As String)

            _Address = value

        End Set

    End Property

    Private _City As String

    Public Property City() As String

        Get

            Return _City

        End Get

        Set(ByVal value As String)

            _City = value

        End Set

    End Property

    Private _Region As String

    Public Property Region() As String

        Get

            Return _Region

        End Get

        Set(ByVal value As String)

            _Region = value

        End Set

    End Property

    Private _PostalCode As String

    Public Property PostalCode() As String

        Get

            Return _PostalCode

        End Get

        Set(ByVal value As String)

            _PostalCode = value

        End Set

    End Property

    Private _Country As String

    Public Property Country() As String

        Get

            Return _Country

        End Get

        Set(ByVal value As String)

            _Country = value

        End Set

    End Property

    Private _Phone As String

    Public Property Phone() As String

        Get

            Return _Phone

        End Get

        Set(ByVal value As String)

            _Phone = value

        End Set

    End Property

    Private _Fax As String

    Public Property Fax() As String

        Get

            Return _Fax

        End Get

        Set(ByVal value As String)

            _Fax = value

        End Set

    End Property

 

End Class

Any guesses on which was faster, which was slowest? The results are in:

  •  
    • LINQ to SQL (12 seconds)
    • ADO Datasets (18 seconds)
    • ADO DataReader (8.9 seconds)

So LINQ is not quite as quick as DataReader but is faster than Datasets.

If you would like to try this out for yourself then cut paste the code above and add it to a module file. In addition you will need to add a LINQ to SQL Class and make sure you call it Northwind.dbml. The only table that is required is the Customers table

 

Guess the movie

Capricorn 15's. Born 2244. Enter the Carousel. This is the time of renewal.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: LINQ
Posted by CynotWhyNot on Friday, April 18, 2008 2:55 PM
Permalink | Comments (125) | Post RSSRSS comment feed

LINQ to XML, Object Graphs and the ListView control

I have a subscription to msdn magazine and am a regular reader. I especially try to read all the articles on any ASP.NET related topics. Dino Exposito is a regular contributor to this magazine and has written many great articles on ASP.NET. In the April 2008 he wrote an excellent article on the new ASP.NET ListView control, specially, he discusses in detail how to bind a ListView control to hierarchical data.

This is by no means the first article that I have read on the topic of ListView controls. In all the articles or blog postings that I have read, I have yet to see how to use LINQ to create custom objects with complex object graphs. Instead anonymous types are used. In this post I will demonstrate how to create a custom object graph from a LINQ to XML query. Furthermore, I will bind this object to a nested ListView control. I will use the same example as presented by Dino in the August edition of msdn magazine.

We will be creating a hierarchical menu that is rendered using LINQ to XML, ListView control and an XML file. Listing 1 shows the menu.xml file.

Listing 1: menu.xml

<?xml version="1.0" encoding="utf-8" ?>

<menu>

  <item>

    <title>Menu Title 1</title>

    <link url="url1-1" text="text1-1"></link>

    <link url="url1-2" text="text1-2"></link>

    <link url="url1-3" text="text1-3"></link>

    <link url="url1-4" text="text1-4"></link>

  </item>

  <item>

    <title>Menu Title 2</title>

    <link url="url2-1" text="text2-1"></link>

    <link url="url2-2" text="text2-2"></link>

    <link url="url2-3" text="text2-3"></link>

  </item>

  <item>

    <title>Menu Title 3</title>

    <link url="url3-1" text="text3-1"></link>

    <link url="url3-2" text="text3-2"></link>

  </item>

</menu>

The schema of this XML file is straight forward. Each <item> node contains a menu title and then has 1 or more links. Each link has the URL to navigate too and the title that is to be used as textual display for the link.

Ultimately we would like to bind this data to a nested ListView control. The markup for this nested ListView control is shown in Listing 2. The title is render in the outer ListView control, whereas, the links are render in the inner ListView control. The code bind will be responsible for binding the outer ListView. The inner is bound declaratively. Please note that DataSource for the inner ListView control must be named links.

List 2: Nested ListView Control

    <asp:ListView ID="ListViewMenu" runat="server" ItemPlaceholderID="PlaceHolder1">

 

      <LayoutTemplate>

          <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>

      </LayoutTemplate>

      <ItemTemplate>

 

        <h1><%# Eval("title")%></h1>

 

        <asp:ListView ID="ListViewSubMenu" runat="server"

          DataSource='<%# Eval("links") %>' ItemPlaceholderID="PlaceHolder2">

 

          <LayoutTemplate>

            <ul><asp:PlaceHolder ID="PlaceHolder2" runat="server"></asp:PlaceHolder></ul>

          </LayoutTemplate>

 

          <ItemTemplate>

            <li><a href='<%# Eval("url") %>'><%#Eval("text")%></a></li>

          </ItemTemplate>

 

        </asp:ListView>

      </ItemTemplate>

    </asp:ListView>

Before we use custom objects, let's review how we can use LINQ to XML and anonymous types as a data source to a ListView control. Listing 3 shows the code behind that accomplishes this.

List 3: Binding ListView Control with an Anonymous Type

        Dim doc As XDocument = XDocument.Load(Server.MapPath("App_Data/Menu.xml"))

        Dim menu = From mi In doc.<menu>.<item> _

                   Select _

                        title = mi.<title>.Value, _

                        links = From link In mi.<link> _

                                Select _

                                    url = link.@url, _

                                    [text] = link.@text

 

        ListViewMenu.DataSource = menu

        ListViewMenu.DataBind()

In this code snippet we are using the LINQ to XML features of VB.NET to query the XML file. The doc.<menu>.<item> retrieves all the <item> children for the document. The content of the <item> node is loaded into an anonymous type having two properties; title and links. The property links is a collection that is populated by the sub query. In the end, the anonymous type, menu is of type IEnumerable(Of <anonymous type>). The menu object is then used as data source to the outer ListView control.

Anonymous type are great, however, there are cases when you may need to pass the data between methods, tiers or even across process boundaries. In this scenario you should us a custom type. To do this you must first create the classes. In our case two classes are required. Listing 4 shows the two classes.

List 4: Custom Types 

<DebuggerStepThrough()> _

Public Class Menu

    <DebuggerBrowsable(DebuggerBrowsableState.Never)> _

    Private _title As String

    Public Property title() As String

        Get

            Return _title

        End Get

        Set(ByVal value As String)

            _title = value

        End Set

    End Property

    <DebuggerBrowsable(DebuggerBrowsableState.Never)> _

    Private _links As IEnumerable(Of Link)

    Public Property links() As IEnumerable(Of Link)

        Get

            Return _links

        End Get

        Set(ByVal value As IEnumerable(Of Link))

            _links = value

        End Set

    End Property

End Class

 

<DebuggerStepThrough()> _

Public Class Link

    <DebuggerBrowsable(DebuggerBrowsableState.Never)> _

    Private _url As String

    Public Property url() As String

        Get

            Return _url

        End Get

        Set(ByVal value As String)

            _url = value

        End Set

    End Property

    <DebuggerBrowsable(DebuggerBrowsableState.Never)> _

    Private _text As String

    Public Property text() As String

        Get

            Return _text

        End Get

        Set(ByVal value As String)

            _text = value

        End Set

    End Property

End Class

The two classes are named, Menu and Link. Menu contains two properties; title and links. links is of type IEnumerable(Of Link) which is important as LINQ queries of this type return the generic type IEnumerable(Of T). I have tried other generic types that derive from IEnumerable(Of T) such as List(Of T) but they generate Unable to cast object of type... exception. Perhaps there is a way to explicitly cast the object but that would require further investigation. Perhaps a future blog post?

Listing 5 shows LINQ to XML code to make use of the custom type.

List 5: Binding ListView Control with a Custom Type

        Dim doc As XDocument = XDocument.Load(Server.MapPath("App_Data/Menu.xml"))

        Dim menu = From mi In doc.<menu>.<item> _

                   Select New Menu With { _

                        .title = mi.<title>.Value, _

                        .links = From l In mi.<link> _

                                Select New Link With { _

                                    .url = l.@url, _

                                    .[text] = l.@text _

                            } _

                    }

        ListViewMenu.DataSource = menu

        ListViewMenu.DataBind()

The menu object is now of type IEnumerable(Of Menu), which can be easily passed as a parameter to a method or serialized across the wire.

Guess the movie

You loved my father, I know. But so did I. That makes us brothers, doesn't it? Smile for me now, brother.

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: ASP.NET | VB.NET | LINQ | XML
Posted by CynotWhyNot on Wednesday, April 16, 2008 4:10 PM
Permalink | Comments (44) | Post RSSRSS comment feed