CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

John Papa [MVP C#]

.NET Code Samples, Data Access, and Other Musings

August 2005 - Posts

  • Dual Core Processor for Visual Studio.NET Development

    I finally broke down and bought a new development PC. And to those who read my post on how my hard drive blew on my last PC twice, in addition to backups I got a RAID 1 array in this PC.  But the coolest part of this story is how fast I can load projects, develop, and make builds with the new dual core processor. [:D] Even with loading a project with ReSharper (which is a very slow loading tool) Visual Studio.NET loads my project quickly. I bought a 3ghz dual core processor (not Extreme Edition, didn't have the cash for that). I would not have thought the dual core would have sped things up so much because it is not really multi tasking much in development, but it did make a big difference for me. It is probably because my PC also does a lot of oother things at the same time (web surfing, SQL Server jobs, serves ASP.NET pages, and some multimedia. My wife laughs at me because the PC is never fast enough. Frankly I don't know exactly why it is so much faster, but I am thrilled that it is!

    I'll be running some tests to see how things compare against benchmarks I ran on my former development PC over the next few weeks. It will be interesting to see how that turns out.

    Of course, I had to go buy a new PC game to see how it works in a dual processor environment too. So I picked up a role playing game called Dungeon Siege 2 last night. I am not much of a gamer because frankly I don't ever find the time. But I am deterined to give this one a shot. I'll post more on that experience later.

  • Displaying the Contents (and Row Versions) of an ADO.NET DataSet

    Was asked for this code a few days ago after a quick demo I did, so I thought I'd throw it out here. Its a quick code snippet that displays the contents of a DataSet for debugging purposes. But first, here is a quick code snippet that grabs a DataSet full of 2 DataTables.

            private void GetData()
            {
                string cnStr = @"server=Mine;database=northwind;integrated security=true;";
                SqlConnection cn = new SqlConnection(cnStr);
     
                DataSet ds = new DataSet("MyDataSet");
     
                string customerSql = "SELECT CustomerID, CompanyName, City, Country"
                                       + " FROM Customers ORDER BY CompanyName";
                SqlCommand customerCmd = new SqlCommand(customerSql);
                customerCmd.CommandType = CommandType.Text;
                customerCmd.Connection = cn;
                SqlDataAdapter da = new SqlDataAdapter(customerCmd);
                da.Fill(ds, "Customers");
     
                string orderSql = "SELECT OrderID, CustomerID, OrderDate "
                                     + " FROM Orders ORDER BY OrderDate DESC";
                SqlCommand orderCmd = new SqlCommand(orderSql);
                orderCmd.CommandType = CommandType.Text;
                orderCmd.Connection = cn;
                da.SelectCommand = orderCmd;
                da.Fill(ds, "Orders");
     
                DisplayDataSet(ds, "My Data");
            }

    And here is the code snippet that iterates through the DataSet to show the DataTables:

            private void DisplayDataSet(DataSet ds, string title)
            {
                Debug.WriteLine(title);
                //--- Loop through the DataTables
                foreach (DataTable table in ds.Tables)
                {
                    Debug.WriteLine("*** DataTable: " + table.TableName + "***");
                    //--- Loop through each DataTable's DataRows
                    foreach (DataRow row in table.Rows)
                    {
                        //--- Display the original values, if there are any.
                        if (row.HasVersion(System.Data.DataRowVersion.Original))
                        {
                            Debug.Write("Original Row Values ===> ");
                            foreach(DataColumn column in table.Columns)
                                Debug.Write(column.ColumnName + " = " + 
                                     row[column, DataRowVersion.Original] + ", ");
                            Debug.WriteLine("");
                        }
                        //--- Display the current values, if there are any.
                        if (row.HasVersion(System.Data.DataRowVersion.Current))
                        {
                            Debug.Write("Current Row Values ====> ");
                            foreach(DataColumn column in table.Columns)
                                Debug.Write(column.ColumnName + " = " + 
                                     row[column, DataRowVersion.Current] + ", ");
                            Debug.WriteLine("");
                        }
                        Debug.WriteLine("");
                    }
                }
            }

    The code is pretty straightforward for DisplayDataSet. I loop through each table in the DataSet, then through the rows in each table, and finally through the columns in each row. Before checking each column, however, I first check to make sure the row has an Original version and/or a Current version. This is nice for displaying the original and current versions of a column's value when you allow the user to edit multiple rows and send all of the changes to the server in a batch. If you don't check if the row has an original version first and the row happens to have been a new row, then it will throw an exception.

    I often take this code and modify it for the debugging purpose of the moment. I've used a couple that throw them into hierarchical DataGrids and make everything nice and pretty. But sometimes I just want a quick and dirty method with a quick and drity code base like this. There are tools out there that you can download to do this, but if all you need is a quick method to display the data and its row versions, this will do nicely too.

    Oh ... and the code above assumes the following using statements:

    using System;
    using System.Data;
    using System.Diagnostics;
    Posted Aug 17 2005, 01:54 AM by John Papa with 5 comment(s)
    Filed under:
  • What's New in Ent Lib 2.0?

    Scott Densmore discusses some of the new features in the upcoming release of Enterprise Library 2.0 and how they are trying to get it inline with Whidbey. He also blogs here (in proxy for Fernando Simonazzi) about Dependency Injection, too.

    Posted Aug 16 2005, 08:26 PM by John Papa with 2 comment(s)
    Filed under:
  • SubString in an ADO.NET DataSet - (DataColumn Expression)

    One cool feature that I just love are the expression based columns in ADO.NET. I do not use them often but when I do find cause to use them, they are very useful. (Not to mention very cool.) One good use of expression columns in a DataSet is when you want to load a column into a DataGrid but you don't want the entire text description to appear in the column. This is often found when you have a notes, comments or some sort of very long description column that is 100 or even 8000 characters long. You likely don't want to show the entire text string because it could stretch out your grid, so a common way to deal with it is to only show the first X amount of characters. For example, the code sample below will create an expression column called "Co" and add it to the Customers DataTable. This new column will grab the first 10 characters from the CompanyName (from the same DataRow in the DataTable) and append 3 dots. So instead of showing all of the columns in a grid, you could hide the CompanyName and instead show the Co column.

     

        string cnStr = @"Data Source=mysqlserver;Initial Catalog=northwind;Integrated Security=True";
        SqlConnection cn = new SqlConnection(cnStr);
        string sql = "SELECT CustomerID, CompanyName, City FROM Customers ORDER BY CustomerID";
        SqlCommand cmd = new SqlCommand(sql, cn);
        SqlDataAdapter da = new SqlDataAdapter(cmd);
        DataSet ds = new DataSet();
        da.Fill(ds, "Customers");
        ds.Tables["Customers"].Columns.Add("Co.", 
            typeof(string), 
            "Substring(CompanyName, 1, 10) + '...'");

     

    There is a WHOLE bunch more that you can do with expression based columns, but I'll leave that for later.

    Posted Aug 11 2005, 11:00 PM by John Papa with 3 comment(s)
    Filed under: ,
  • Incrementing in .NET (i++ vs ++i)

    I was working with some friends on some unit testing when we recently ran across an issue that was caused by an uninteded use of an incrementor (++). It was  quick fix but it is also something I have seen quite often, so I figured I would jot my thoughts down while it was fresh in my mind.

    So we've all seen the common for loop in .NET, looping a finite number of times.

                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine(i.ToString());
                }

    This above example outputs a list of numbers 0 through 9. And at times we need to loop through one variable (like i in the above example) yet increment another counter variable. So we do something like the below example:

                int j = 0;
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine((j++).ToString());
                }

    Nothing wrong with this. It loops 10 times and increments j. This above snippet outputs a list of numbers 0 through 9.

    I recently was asked to debug some code that looked a little more like this:

                int k = 0;
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine((++k).ToString());
                }

    Again, it loops a finite number of times (10) and increments a separate counter variable (k in this case). But this time the out put is slightly different than the previous 2 examples. This code snippet outputs 1 - 10. The reason is obvious when you strip out all of the other code that was there already ... the incrementor (++) appears before the k in this example. Thus, k is incremented, then the ToString() method operates on it. In the previous example, j variable's value is output and THEN the incrementor (++) operates on the j variable.

    Not difficult to see in this case, of course. But the developer who was working on this was assured that x++ and ++x always responded the same, no matter the situation. Well, in MANY cases this is true. The above example could be modified so the incrementor preceeding or following the varialbe won't matter ... like either of these following code samples:

                int x = 0;
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine(x.ToString());
                    x++;
                }
     
                int y = 0;
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine(y.ToString());
                    ++y;
                }

    Both of these samples output 0-9 ... and both of these are much easier to read and less apt to wreak havoc than the previous inline examples.

    OK, I am running out of letters for examples, gotta run!

    Posted Aug 10 2005, 10:01 PM by John Papa with 11 comment(s)
    Filed under:
  • Find SQL Server Stored Procedures Containing Some Text

    Relatively basic stuff here, but I do like to stick to the KISS rule. I am often required to search SQL Server's stored procedures to find out which ones refer to specific fields, tables, or even variable names. Recently, I had to refactor several stored procedures defined a specific alias for a column. Being the geek that I am, I wrote a little stored proc helper routine that quickly came up with the results I needed. In my case, there were over 1000 procs to search and my results turned up 25 procs to refactor.

    CREATE PROCEDURE sp_find_procs_containing
        @search VARCHAR(100) = ''
    AS
    SET @search = '%' + @search + '%'
    SELECT    
         ROUTINE_NAME,
        ROUTINE_DEFINITION
    FROM    
        INFORMATION_SCHEMA.ROUTINES
    WHERE    
        ROUTINE_DEFINITION LIKE @search
    ORDER BY
        ROUTINE_NAME
    GO

    If you invoke this proc and pass it the phrase you are looking for in the proc, it will return them in sorted order. Not brain surgery, just something to help me code faster.

    As you can tell, I like the INFORMATION_SCHEMA views. Here is another post I put up a while back on using them.

    Posted Aug 09 2005, 04:58 PM by John Papa with 12 comment(s)
    Filed under:
  • T-SQL: IF NOT EXISTS versus @@ROWCOUNT

    I was asked a good question the other day regarding why I chose to use "IF NOT EXISTS" in my Nov 2003 MSDN article on User Defined Functions to check to see if a declared table variable had any rows in it versus checking @@ROWCOUNT. Mostly I chose to use IF NOT EXISTS because I know that I find it less apt to break on me in case I do something silly. For example, if I chose to check @@ROWCOUNT in the SQL sample code below instead of using "IF NOT EXISTS", it works just fine. But what happens if I (or someone else) adds another SQL statement at line 15 that alters the @@ROWCOUNT? For example, If I augment this code in the future to inlcude an UPDATE statement at line 15, the ROWCOUNT will no longer represent the number of rows affected by the INSERT statement (lines 10-14). Is this likely to happen? Probably not. Has it happened to me? Oh yeah, I was burnt once on this. Is it bad to use ROWCOUNT? Not at all! I was being overly careful in this code example and also wanted to show how "IF NOT EXISTS" works. So the answer is that both ways work.

     

        1 CREATE FUNCTION fnGetEmployeesByCity3 (@sCity VARCHAR(30))

        2     RETURNS @tblMyEmployees TABLE

        3     (

        4         FirstName VARCHAR(20),

        5         LastName VARCHAR(40),

        6         Address VARCHAR(120)

        7     )

        8 AS

        9 BEGIN

       10     INSERT   @tblMyEmployees

       11     SELECT   FirstName, LastName, Address

       12     FROM     Employees

       13     WHERE    City = @sCity

       14     ORDER BY LastName

       15 

       16     IF NOT EXISTS (SELECT * FROM @tblMyEmployees)

       17         INSERT @tblMyEmployees (Address)

       18             VALUES ('No matching employees found in the specified city')

       19 

       20     RETURN

       21 END

    Posted Aug 05 2005, 11:23 AM by John Papa with 16 comment(s)
    Filed under:
  • Thoughts on Dell Dimension and Dell Support

    A few months ago I am finishing up my article on System.Transactions for MSDN Magazine at about 3am, decide to hit the sack and review the article one last time before I submit it the next day (the due date). I get up around 8am and go to look at it and the PC locks up and shuts down. I'm softly saying "no, no, no!". I boot up, and it says "bwahahahaha! your hard drive is toast!" Greaaaaaaaaaaaaaaaaaaaaaaaaat! Long story short, I lost the article. No, I did not back it up. Everything else was backed up just a day earlier, but I had not yet backed up my article nor had I emailed it so I could not even go to the email server to get it. ugh. Thankfully, the MSDN crew were very good to me and let me have a few extra days to recreate my article (oh, that was fun ... talk about deja vu!).

    So now I have my new hard drive ... and guess what ... today the hard drive blew again and the CPU fan blew on me! I am so happy!!! NOT! Anyway, the Dell support was very helpful once again. They are sending me the new parts and a person to install them for me. yes I could do it on my own but I am paying for next business day support so why not take advantage of it? Overall I am very happy with the next business day support from Dell. I have 4 Dell computers, only 1 of which has had any hardware failures. But on both of the occasions where the parts failed the phone support was quick to get to (under 3 minutes) and they were quick to get the parts out to me and a technician on the way. Today, I did have to request a technician come out instead of them overnighting the parts to me. That bugged me a little, but he gave in quickly and agreed.

    So I spect about $180 for 3 yr next business day service and I got out of it a new CPU fan and 2 new hard drives not to mention next day installation by a technician. So the cost was well worth it for me, especially since I am a developer and this is my main development PC. Overall I give it a thumbs up.

    I am considering getting a new PC sometime this year and was thinking about skipping the NBD service from Dell this time. I think my experiences have now proven that for me, it is well worth the extra money. I am now considering possibly getting the Dimension with the dual core processor. If I do, I will blog about how it does or doesn't help speed anything up.

    Day 1: OK, they never showed up the next business day nor did they call! At least a phone call or email would have been nice.

    Day 2: Dell still hasn't showed. I called them and they say they can't promise a time. </sigh>

    Day 3: Where is Dell? Not here. I called them and they say they are sorry but they can't promise a day or time.

    Business Day 4:  Didn't call them today. Was hoping they would just show up. It's been 6 days or 4 business days. Thankfully I have another computer. 

    Day 5: No word once again, Dell says they should be here.

    Day 6: Ah, finally someone at Dell tells me that someone did not enter the support call correctly and that nobody has been dispatched. The call has been re-entered and they now say it is likely for Friday (8th business day). Can't wait for the service survey they always send me.

    Day 7: Service tech arrives with the parts, installs them, takes off. Very professional and quick. Can't complain about his service. If the original guy I talked to had just entered the call correctly or someone had caught it, this all would've been fixed a week ago. </rant>

  • Coming to Orlando in October

    VSLive Boston in late June was fun. I spoke on 2 topics (one regarding the new features of ADO.NET 2 and the other one regarding System.Transactions). I had a good time talking to several attendees at VSLive including a couple of our codebetter blog readers. One thing I love about presenting at conferences is that I get to meet really interesting and great people.

    I just confirmed that I will also be presenting 2 different topics at VSLive Orlando in October. You can check out the schedule of presentations for VSLive Orlando here. The topics and their brief summaries are below. Once I get the slides for these to a more completed state I will post their agendas as I did with the Boston ones here and here. I'll be wearing my codebetter.com polo shirt, so track me down if you will be there too.

    Efficient Data Access with ADO.NET and SQL
    Using an efficient data access strategy is essential in designing scalable and efficient enterprise solutions. In this session I will review several data access techniques that can improve performance and/or ease maintenance in applications. I’ll discuss efficient ways to implement ADO.NET database connections, automatic closure of connections and using connection pooling. I will also review some performance and efficiency tips when executing stored procedures, using parameterized queries, and preventing SQL injection attacks.

    Editing Master and Detail Records in ASP.NET 2.0
    The ASP.NET 2.0 GridView and DetailsView controls add tremendous value to developers who need to create editable web forms with master detail data. These controls reduce the amount of code required to page, sort and handle many events that formerly required custom event handlers. This session will demonstrate how to migrate code to these controls from the ASP.NET 1.x DataGrid in a mutli tier application.

  • Enterprise Library - Data Block Changes

    If you have not checked out the latest build of Ent Lib, you can get the Enterprise Library – June 2005 release here. The list of changes can be found here, as well. Borrowing from their master list, the list of changes to the Data Access Application Blocks are as follows:

    • The new method named GetStoredProcCommandWrapperWithSourceColumns is added to the Database class. This method provides creation of a stored procedure command wrapper whose parameter values come from source columns in a DataTable. In addition, new public methods provide access to the DbDataAdapter object for the current database connection.
    • The DataConnectionFailedEvent and DataConnectionOpenedEvent classes are updated to be thread safe.
    • The OracleCommandWrapper class is updated to perform proper conversion between parameters of types not recognized by Oracle and native Oracle types.

    If you haven’t jumped into the Ent Lib yet, its worth a good look. The code is open so you can build on what you don’t like or leave it as is. You can also use some blocks and ignore others (as I do). I am looking forward to the next version (v 2.0). If you are too, check out Tom Hollander’s blog occasionally as well. He often has good posts on Ent Lib. If you are looking to jump in, you can take a look at Part 1 and Part 2 of my 3 part series on the Data Access Applicaiton Block online at MSDN Magazine.

    I’ve received a lot of good feedback on these articles with a lot of good questions and what if scenarios. Unfortunately, IU have not been able to keep up with the number of responses I have received so please don’t think I am ignoring you if I don’t get back right away. I do read all of my email and I appreciate all of your input, so please keep it coming and I will try to respond as much as I can.

More Posts