Dabbling in LINQ to ADO.NET

Published 5 January 8 9:13 PM | William

I'll be doing a training seminar in Stockholm next month and I've been trying to create some compelling examples to illustrate various concepts.  Although it's keeping me busy, there's a  lot I've been working on that's blogworthy.

One concept in LINQ to SQL that's I am pretty fond of is the use of Entities. There's so much you can do with Entities that it would take quite a few posts to do them justice, but I'll show a simple example of how they can be used.  Assuming we're using SQL Server 2005 for this example, I have a database table with the following table definition:

GO /****** Object: Table [dbo].[Bank] Script Date: 01/05/2008 21:14:48 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Bank](
             [BankID] [int] IDENTITY(1,1) NOT NULL,
             [Name] [varchar](150) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, 
             [URL] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
             [bigLogo] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
             [smallogo] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
             CONSTRAINT [PK_Bank] PRIMARY KEY CLUSTERED (
           [BankID] ASC )
           WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF
          ,ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)

          ON [PRIMARY] )
          ON [PRIMARY]
       GO
SET ANSI_PADDING OFF

So the first thing we need to do is create a class with the same definition (note, if you are using a member name that's the same as the column name in the db, no additional steps need taken. If you use different names, then you need to specify a Name value .  Field names are not case sensitive [meaning as long as they have the same spelling as the field in the db, the capitalization can be different]). So you use [Column(Name="DBColumnName")] public Type AliasNameYouWantToUse

using System.Linq;
using System.Linq.Expressions;
using System.Data.Linq.Mapping;
namespace Ryan.Samples.Linq.ADONET {
     [Table(Name="Bank")]
     public class Bank {
     [Column]
     public Int32 BankID;
     [Column]
     public String Name;
     [Column]
     public String URL;
     [Column]
     public String biglogo;
     [Column]
     public String smallogo;
    }
}

Now, we have a Bank class which corresponds to the Bank table in the database.  For this sample, I created a static class with a static property named Globals and ConnectionString respectively.  Now, I compose a quick LINQ query to retrieve all of the data in the table except records where the Bank's Name is PNC:

static void Main(string[] args)
{
   DataContext db = new DataContext(Globals.ConnectionString);
   Table <Banks> = db.GetTable<Bank>();

     var query =
           from b in Banks
           where b.Name != "PNC"
     select new { b.BankID, b.Name, b.URL };

     foreach (var row in query)
     {
         Console.WriteLine(row);
     }
     Console.ReadLine();
}

The syntax is pretty straightforward on the LINQ side so it doesn't really need explaining - if you can't tell what it's doing though, it's selecting each value that doesn' t have 'PNC' as a name.  The Select statement is using a new C# language feature known as Anonymous types meaning that, a new type is being created without a traditional definition - that's why the new keyword is used.

When I first learned LINQ though, I wondered how this worked.  Was the whole table retrieved from the database and then records restricted via LINQ?  If so, this would seem very wasteful b/c by virtue of the restriction, you know you're only using a subset of the total values so why pull down everything?  Fortunately that's not what happens.  GetTable doesn't acttually pull down everything from the table - it's merely an instruction about how to generate the query it will use. As you probably have noticed, nowhere in here have we defined anything reminiscent of the CommandText property you'd use with a IDBCommand object.  To prove that you aren't pulling down a whole table as you might with the old TableDirect instruction, run profiler before this code block executes.  The results will show the following (assuming you are logging the same values).

Here's the resulting output:

exec sp_executesql N'SELECT [t0].[BankID], [t0].[Name], [t0].[URL]
FROM [Bank] AS [t0]
WHERE [t0].[Name] <> @p0',N'@p0 nvarchar(3)',@p0=N'PNC'

And just for the record, nothing before this ran a query on this table let alone one without a restriction.  The output for running this code is shown below:

{ BankID = 1, Name = Bank of America, URL = www.bankofamerica.com }

{ BankID = 2, Name = Citi Bank, URL = www.citibank.com }

{ BankID = 3, Name = 1st Tennessee, URL = http://www.firsttennessee.com/ }

{ BankID = 4, Name = Citi Group, URL = www.citigroup.com }

{ BankID = 5, Name = JP Morgan, URL = www.jpmorgan.com }

{ BankID = 7, Name = UMB, URL = www.umb.com }

{ BankID = 8, Name = US Bank, URL = www.usbank.co }

{ BankID = 9, Name = BMO Financial Group, URL = www4.bmo.com/ }

{ BankID = 10, Name = M & T, URL = http://www.mandtbank.com/ }

{ BankID = 11, Name = National City, URL = http://www.nationalcity.com }

This brings up one other point... I could have changed the Console.WriteLine to just write out one or more of the properties of 'row'.  In general, I make a rule of *always* overriding the ToString() method in any object I create just so that I can use it for meaningful information. With LINQ in particular, this becomes particularly useful b/c had I not used an anonymous type, (so the last line would read 'select b;' instead of 'select new {b.BankID, b.Name, b.URL}; I would have had the following useless output:

Ryan.Samples.Linq.ADONET.Bank

Ryan.Samples.Linq.ADONET.Bank

Ryan.Samples.Linq.ADONET.Bank

Ryan.Samples.Linq.ADONET.Bank

Ryan.Samples.Linq.ADONET.Bank

Ryan.Samples.Linq.ADONET.Bank

Ryan.Samples.Linq.ADONET.Bank

Ryan.Samples.Linq.ADONET.Bank

Ryan.Samples.Linq.ADONET.Bank

Ryan.Samples.Linq.ADONET.Bank

 I could get around that by formatting the output in the Console.WriteLine method but that's might inelegant. Instead, by overriding the ToString() method, I can get the following output instead:

<I''ve truncated several records just for the sake of readability>

BankID - 1

Name - Bank of America

URL - www.bankofamerica.com

biglogo - baclogo.jpg

smallogo - bigbanksmall.jpg

BankID - 2

Name - Citi Bank

URL - www.citibank.com

biglogo - citibanklogo.jpg

smallogo - bigbanksmall.jpg

BankID - 3

Name - 1st Tennessee

URL - http://www.firsttennessee.com/

biglogo - 1sttennlogo.jpg

smallogo - 1sttennsmall.jpg

Needless to say, this is a lot more useful than simply knowing the fully qualified object name.

 

Search

This Blog

Tags

Community

Archives

News

  • William G Ryan William Ryan Bill Ryan W.G. Ryan Charles Mark Carroll Charles M Carroll
    My Blog Juice Microsoft MVP
    Bill Ryan W.G. Ryan William Ryan
    Cuckooz' MySpace Page View Bill Ryan's profile on LinkedIn
    My Profile on Twitter
    Please note that this is my personal blog and the opinions expressed are my own. Also, comment moderation is about one of the least important things in my life so please keep that in mind. I can't vouch for the authenticity of any of the posters so please don't hold me accountable. And whatever you do, don't pretend to be Noted Option Strict Off expert and AspFriend Charles Mark Carroll when you post. Doing so will lead him to become apoplectic and write absurd accusatory posts about me that are as coherent and thought out as they are factually correct. He does a stellar job proving his reputation is well deserved and he doesn't need any help from you making himself look foolish. If I have to listen to him banging his spoon off of his high chair one more time, I'm going to burst into flames so please don't make that happen!

    My other sites

    Cool Stuff

    Book Stuff

    Security

    ORM

    Data Access

    Funny Stuff

    Compact Framework Stuff

    Web Casts

    My KnowledgeBase Articles

    My MVP Profile

    Design Patterns

    Performance

    Debugging

    Remoting

    My Fellow Authors

    My Books

    LINQ

    Misc

    Speech

    Syndication

    Email Notifications