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

April 2005 - Posts

  • Class Diagrams in Visual Studio.NET Beta 2

    A few days ago Raymond Lewallen blogged about refactoring some VB.NET code using interfaces, and abstract classes. I followed up with a C# example of the same code in a blog. I thought this would be interesting to see how it looks in a VS.NET Beta 2 class diagram. One of the nice features that I like about the tool is that it lets me export an image of the diagram in a variety of formats.

    The class diagram is easy to use … just drag and drop a class onto it. I can right click the classes refactor or add fields, properties, methods, and constants. Nothing glamorous, but when you are a visual developer like me, it often is nice to see the class structure in a diagram like this. Yeah there are tools that do it for you, but now its built in.

    Posted Apr 27 2005, 07:42 PM by John Papa with 5 comment(s)
    Filed under:
  • Project Rally to be Unveiled at Tech Ed

    ASPSOFT has released Trailer #2 for Project Rally, which will be unveiled at Tech Ed (June 5–10 in Orlando, FL).

    And in case you missed it, you can check out Trailer #1 for Project Rally here, as well.

    It is going to be awesome!

     

  • Refactoring - OOP Example from VB.NET to C#

    OK, I don't want to leave out the C# developers from this VB.NET OOP example that Raymond posted recently. So here is one way to accomplish this code in C#.

     

    Inheritence, Interfaces, and OOP (oh my!)
    public class foo
    {
    	public static Int32 GetNumberOfRequiredTokens(IPerson person)
    	{
    		return person.GetNumberOfRequiredTokens();
    	}
    }
    
    public interface IPerson
    {
    	Int32 GetNumberOfRequiredTokens();
    }
    
    public abstract class Person : IPerson
    {
    
    	public Person()
    	{
    	}
    
    	private Int32 baseTokenAmount = 1;
    
    	protected Int32 Tokens
    	{
    
    		get
    		{
    			return baseTokenAmount;
    		}
    
    	}
    
    	public abstract Int32 GetNumberOfRequiredTokens();
    }
    
    public class Child : Person
    {
    	public override Int32 GetNumberOfRequiredTokens()
    	{
    		return base.Tokens;
    	}
    
    }
    
    public class Adult : Person
    {
    	public override Int32 GetNumberOfRequiredTokens()
    	{
    		return base.Tokens * 3;
    	}
    
    }
    
    public class Infant : Person
    {
    	public override Int32 GetNumberOfRequiredTokens()
    	{
    		throw new TooYoungException();
    	}
    
    }
    
    public class TooYoungException : Exception
    {
    }
    
    Posted Apr 26 2005, 07:44 PM by John Papa with 5 comment(s)
    Filed under:
  • Getting GrandParent columns with ADO.NET

    I've recently had a flurry of email asking how to navigate up to a grandparent table using ADO.NET. Assuming that it is not preferable to export all of the data to Xml and use an XPath, ADO.NET offers a few other ADO.NET based solutions. One solution is to use expression based columns. (If you want more of an explanation of how to use expression based columns in ADO.NET, see my Data Points article here in MSDN Magazine.)  

    To explain both solutions, I created a DataSet that contains 3 DataTables. The DataTable objects represent Customers, Orders and Order Details from the SQL Server Northwind database. I also create a DataRelation between the Customers and its child table, Orders. Then I create another DataRelation between the Orders and its child table, Order Details. At the end of this code sample, shown below, I have a DataSet with Customers, their Orders and their Order Details linked through relations.

    Filling the DataSet with Customers, Orders and Order Details
    string sCn = "server=(local);database=northwind;integrated security=true;";
    DataSet ds = new DataSet();
    
    using (SqlConnection cn = new SqlConnection(sCn))
    {
      cn.Open();
      // Get the Customers
      string sqlCustomers = "SELECT CustomerID, CompanyName, Country "
        + " FROM Customers ORDER BY CustomerID";
      using (SqlCommand cmd = new SqlCommand(sqlCustomers, cn))
        using (SqlDataAdapter da = new SqlDataAdapter(cmd))
          da.Fill(ds, "Customers");
      ds.Tables["Customers"].PrimaryKey = 
        new DataColumn[]{ds.Tables["Customers"].Columns["CustomerID"]};
    
      // Get the Orders
      string sqlOrders = "SELECT OrderID, CustomerID, OrderDate FROM Orders";
      using (SqlCommand cmd = new SqlCommand(sqlOrders, cn))
        using (SqlDataAdapter da = new SqlDataAdapter(cmd))
          da.Fill(ds, "Orders");
      ds.Tables["Orders"].PrimaryKey = 
        new DataColumn[]{ds.Tables["Orders"].Columns["OrderID"]};
      ds.Relations.Add("C2O", 
        ds.Tables["Customers"].Columns["CustomerID"], 
        ds.Tables["Orders"].Columns["CustomerID"]);
    
      // Get the Order Details
      StringBuilder sb = new StringBuilder("");
      sb.Append("SELECT od.OrderID, p.ProductID, p.ProductName, ");
      sb.Append(" od.UnitPrice, od.Quantity");
      sb.Append(" FROM [Order Details] od ");
      sb.Append(" INNER JOIN Products p ON od.ProductID = p.ProductID");
      string sqlOrderDetails = sb.ToString();
      using (SqlCommand cmd = new SqlCommand(sqlOrderDetails, cn))
        using (SqlDataAdapter da = new SqlDataAdapter(cmd))
          da.Fill(ds, "Order Details");
      ds.Tables["Order Details"].PrimaryKey = 
        new DataColumn[]{ds.Tables["Order Details"].Columns["OrderID"], 
        ds.Tables["Order Details"].Columns["ProductID"]};
      ds.Relations.Add("O2OD", 
        ds.Tables["Orders"].Columns["OrderID"], 
        ds.Tables["Order Details"].Columns["OrderID"]);
      cn.Close();
    }


    The first solution I mentioned adds an expression column to the Orders and to the Order Details DataTable objects. The expression column in the Orders DataTable navigates up to its parent DataTable (Customers) via a DataRelation and simply gets the value of the Country column. The expression column in the Order Details DataTable navigates up to its parent DataTable (Orders) via a DataRelation and evaluates the expression column in the Orders DataTable to determine if the country is the US or not.

    Grandparent via Expressions
    // add an expression column, to help out
    ds.Tables["Orders"].Columns.Add("CustomerCountry", 
      typeof(string), "Parent.Country");
    ds.Tables["Order Details"].Columns.Add("CountryType", typeof(string), 
      "Iif(Parent.CustomerCountry = 'US', 'US', 'Foreign Country')");
    
    // Find an Order Details Row, just to start things off
    DataRow row = ds.Tables["Order Details"].Rows.Find(new object[] {"10260", "57"});
    
    // Look at the expression column
    Debug.WriteLine(row["CountryType"]);
    

    The second solution does not require expression columns. Instead, it uses the GetParentRow method of the DataRow. In this example, I evaluate the Customers.Country field by travelling up from the Order Details row to its parent Orders row and then up to its grandparent Customers row.
    Grandparent via GetParentRow
    // Use the GetParentRow to get the value instead
    string sCountry = 
      row.GetParentRow("O2OD").GetParentRow("C2O")["Country"].ToString();
    Debug.WriteLine((sCountry == "US")   ? "US" : "Foreign Country");
    
    Posted Apr 23 2005, 01:00 PM by John Papa with 5 comment(s)
    Filed under:
  • I am Joining ASPSOFT

    I am happy to announce that I am joining ASPSOFT (aka the haven of the angrycoder, Jonathon Goodyear). I ran across Jonathon somewhat by accident when I was exploring the job market in southwest Florida, we started talking and after a few weeks I was on board with ASPSOFT. (It's funny that Jonathon and I have never actually met before since we often present at the same conferences.)

    A special thanks to David Hayden, J. Ambrose Little and everyone else who had the patience and the kindness to help me in my search. And of course, thanks to Jonathon for asking me to be a part of his team.

    I look forward to starting in May and working with Jonathon, Ambrose and the ASPSOFT crew. Of course I'll still be blogging here with the crew of codebetter.com and writing for MSDN Magazine and other publications.

     

  • Good Overview of Event Handlers, Delegates

    Scott Stewart gives a good overview of Delegates and Event Handlers in his recent blog. He has some good points regarding how to define events and some of the implications of not using some forethought in designing events.
    Posted Apr 19 2005, 07:07 AM by John Papa with no comments
    Filed under:
  • Post Build Events in VB.NET in Visual Studio.NET 2005 Beta 2

    I was just poking around in Visual Studio.NET 2005 Beta 2 and I noticed that in my VB.NET project there is now the option to create build events! This is a feature that I have used a lot in C# WinForm projects to copy my Enterprise Library configuration files to the targe directory (release or debug). I am glad it is now available in VB.NET (at least in beta 2)!

     

  • Enterprise Library Patch

    Tom Hollander, Product Manager of Enterprise Library, announced that a new patch is out for Ent Lib. It patches a memory leak in the Enterprise Library Configuration Application Block, which is used by all of the other blocks. I downloaded it, installed it and was done within minutes. Testing several apps that use Ent Lib showed that everything was well for my applications. You can go to the Ent Lib community site and download the patch (you need to join the community to get the patch).

    The patch contains 2 files:

    • ConfigurationManager.cs
      • The source file that they made the changes to for the Config block
      • I glanced through this and it looks like they removed the finalizer and the 2 dispose methods
    • Patch 1475 Readme.htm
      • Contains installation instructions and details on the issue

    Here are the installations instructions, excerpted from the Readme file:

    1. Copy the included file ConfigurationManager.cs into [Enterprise Library Installation Directory]\src\Configuration. By default, Enterprise Library is installed to "C:\Program Files\Microsoft Enterprise Library". A file with the same name will already exist in the location. If you have made any updates to this file yourself, you should make a backup copy first.
    2. Open up EnterpriseLibrary.sln in Visual Studio .NET, either by opening the file from the .\src folder or choosing the "Enterprise Library Solution" shortcut on the Start Menu.
    3. Choose Build Solution from the Build menu to rebuild all projects in the Enterprise Library solution.
    4. Verify the solution successfully builds and close Visual Studio .NET.
    5. Open the Start Menu, find the Enterprise Library folder and run the "Copy assemblies to bin directory script".
    6. Delete any other copies of Microsoft.Practices.EnterpriseLibrary.Configuration.dll that you have on your system, and replace them with the newly built version in .\bin directory.
    7. Recompile any applications that use Enterprise Library.

     

    Posted Apr 17 2005, 11:06 AM by John Papa with 1 comment(s)
    Filed under:
  • First Impressions of BlogJet

    I’ve been using BlogJet for a few weeks now to post to my blog and while it has not overwhelmed me, it has proven to be a useful tool. Here are some quick observations that I have made regarding the pros and cons that are important to me:

    Pros:

    • It is nice to be able to post to my blog without having to go to my blog’s web page
    • I can save drafts of my postings locally or post them as non published to my blog
    • Basic formatting such as bullets, hyper links, fonts and images are easy
    • Associating my post with 1 or more categories from my blog is easy
    • I can date my blogs in the future for a future release
    • It has spell check (disabled by default)

    Cons:

    • Setting it up was not as easy as I would have hoped since I had to figure out what Provider to select and what web page to point it to for Community Server. (Thankfully, other codebetter.com crewmen had already been down that road.)
    • If it had built in code formatting for code samples, well, that would be awesome. (Currently I use a custom program I wrote as well as a program called CopySourceAsHtml for formatting code.)

    I don’t have any serious complaints with BlogJet so I will continue using it.  

    Eric Wise did a quick review of BlogJet a few weeks ago, as well.

    Posted Apr 16 2005, 09:46 PM by John Papa with 5 comment(s)
    Filed under:
  • ASP.NET 2 QuickStarts / Tutorials are Available

    If you want to get a head start on ASP.NET 2, check out the ASP.NET 2 QuickStarts Tutorial. It's all beta, so of course treat it as such. I've played with a few of them and there is some decent stuff out there already. Code samples are avaialble in C# or VB.NET, as well.
    Posted Apr 14 2005, 06:33 PM by John Papa with 2 comment(s)
    Filed under:
  • Comments to MSDN Magazine

    I have been writing for MSDN Magazine for almost 7 years with what started out as feature articles and moved into my current Data Points column. 7 years is a long time and is it suggests, I love working for them. I get a lot of comments via email from readers and despite the volume, I do read all of them. I don't have the time to reply to all of them, although I do try my best. For those of you who send comments in, thank you ... I enjoy hearing feedback on what you liked, thought could be improved, was left out, what would be valuable for future articles.

    Every now and then, the MSDN Magazine crew sends us all the comments that people have posted as they're rating the articles. Most of them are helpful, and most are very positive and have great comments. I get a few that rate my articles 1 out of 9 but then say the article was great ;-) I also get a few that rate it 1 out of 9 and simply did not like the article's content. I appreciate all of the feedback. I really do. So please keep it coming, I hope you enjoy them!

    NOTE: Ken Getz blogged today about his MSDN comments, too.

     

    Posted Apr 14 2005, 07:25 AM by John Papa with no comments
    Filed under:
  • DataTable Becomes a Real Boy in ADO.NET 2

    I am really excited about some of the new features in ADO.NET 2. I posted here last month regarding how the ADO.NET 2 DataTable class will expose a Merge method (woo hoo!). I found this very useful when I had DataTable's to merge but no DataSet (and thus had to create a DataSet just to merge the DataTable objects -- yuk!)

    Anyway, there are other situations where I had a DataTable sans a DataSet and I had to create a DataSet just to take advantage of some features it had that the DataTable didn't. In ADO.NET 2, a lot of attention appears to have been paid to the DataTable as it now has many of the features of the DataSet. For example, in ADO.NET 2 you can get the following method on a ADO.NET 2 DataTable that were formerly only available in a DataSet:

    • Merge
    • ReadXml
    • ReadXmlSchema
    • WriteXml
    • WriteXmlSchema

    I never liked how the DataTable did not have the xxxXml method in its arsonal. But at least the next incarnation of ADO.NET will have incldued many of the features that the DataSet already has ... a bit of catch-up, I guess.

    I'm very excited about the ability to create a DataTable from a DataView, the DataTable's new GetDataReader method, the fact that I can now change the DataRow.RowState manually, and the plethora of other features as well! I'm having fun putting together some code samples for VSLive, MSDN Magazine and my codebetter.com blog on these cool ADO.NET 2 features!

     

  • May 2005 Issue of MSDN Mag and Data Points

    The May 2005 issue of MSDN Magazine is now available online at http://msdn.microsoft.com/msdnmag/issues/05/05/DataPoints/default.aspx.

    After a 2 month break, my Data Points column is back. In this issue I discuss several Data Access Strategies Using ADO.NET and SQL, inlcuding some tips on writing queries, connection maintenance and building more efficient commands.

    In case you are wondering what my next few Data Points columns will cover, here is a sneak peek:

    • Using the FOR XML clause in SQL statements and how to access it via ADO.NET
    • Configuring the Enterprise Library Data Access Application Blocks (including configuration, cryptography and where Ent Lib is useful)
    • Implementing the Enterprise Library Data Access Application Blocks (exensive examples on how to use it, which methods to use, and so on)
    • ADO.NET v2 (what's in it, how it has been improved, how you can get started with it, what to look out for)
  • ADO.NET Performance Test: Getting a Single Value

    I ran some tests using ADO.NET to measure the time it takes to retrieve a single value from a database. All of my tests had the following attributes:

    • Each test gets the CompanyName for the specified CustomerID (in Northwind)
    • The same connection string, using integrated security
    • Stored procedure (vs inline SQL)
    • I used a SqlCommand with a parameter for the input value (and the output, for the output parameter test)
    • I ran the stored procedures ahead of time to remove the possibility of the first time performance hit
    • SqlConnection, SqlCommand and the SqlDataAdatper (where applicable) all used the using statement
    • I added the result to a list box in each test, just to show that we did something with the value
    • I ran the complete tests over 25,000 iterations, including destruction of all ADO.NET objects (and instantiation)

    The techniques that I tested were:

    • ExecuteScalar 
      • Retrieving the CompanyName from a stored procedure as the return value of the ExecuteScalar method
    • Output Parameters
      • Retrieving the CompanyName from an output parameter of a stored procedure
    • DataSet
      • Retrieving the CompanyName from the first row amd colun of a DataSet, as the result of a stored procedure

    Here were the test results:

    So it turns out that ExecuteScalar test ran slightly faster than the output parameter test, and much faster than the DataSet test. In case the image comes ut fuzzy, here are the results again:

    Test Iteration Elapsed ms
    ExecuteScalar 1 6577
    ExecuteScalar 2 6468
    ExecuteScalar 3 6577
    Output Parameter 1 6780
    Output Parameter 2 6671
    Output Parameter 3 6749
    DataSet 1 10655
    DataSet 2 10608
    DataSet 3 10608

    Given that ExecuteScalar is easier to implement that an output parameter, I'd choose that over output parameters. But it is interesting that ExecuteScalar and using output parameters are so close. I found it very interesting to see how slow the DataSet technique was. Kind of figured that it would be slower, but that was somewhat surprising (the DataSet is onyl returning a single row and column).

    In case you are wondering, I ran the tests again over iterations of

    • 1000
    • 10,000
    • 100,000
    • 250,000

    The results were very similar in each case. When I ran the tests for less than 1000, sometimes it ran so quick that the results were 0 ms. Not much help there ;-)

    Anyway, I thought it was interesting to see the results of how well or porrly these 3 methods performed. You might wonder why I did not try the DataReader ... well, I'll try that one and re-post later.

    The ExecuteScalar Test
    case "ExecuteScalar" : 
      dteTimer = DateTime.Now;
      for (int i = 1; i <= iLimit; i++)
      {
        using (SqlConnection cn = new SqlConnection(sCn))
        {
          string proc = "prGetCustomerName";
          cn.Open();
          using (SqlCommand cmd = new SqlCommand(proc, cn))
          {
            cmd.CommandType = CommandType.StoredProcedure;
            SqlParameter parmCustID = new 
              SqlParameter("@CustomerID", SqlDbType.NVarChar, 10);
            parmCustID.Direction = ParameterDirection.Input;
            parmCustID.Value = "FRANK";
            cmd.Parameters.Add(parmCustID);
            sCompany = cmd.ExecuteScalar().ToString();
            lstResults.Items.Add(i.ToString() + ") " + sCompany);
          }
          cn.Close();
        }
      }
      dblPeriod = TimeSpan.FromTicks(DateTime.Now.Ticks - 
        dteTimer.Ticks).TotalMilliseconds;
      lstElapsedTime.Items.Add("ExecuteScalar: " + 
        dblPeriod.ToString() + " ms");
      break;
    Posted Apr 10 2005, 09:57 PM by John Papa with 3 comment(s)
    Filed under:
  • It's not ADO.NET for Toddlers

    I've always wanted to write. I love Tolkien's LOTR, Shakespeare (MacBeth is my favorite ... yeah, I know its dark, but it really grabbed me), Chaucer's Canterbury Tales, Beowulf (very cool monsters), and Homer's the Illiad (The Odyssey is just alright). I knew I was never going to be at that level, and with my career choice being what it is, technical books and magazine articles seemed like a good way to both write and stay in my career path. In fact, I am in the throws of planning a few upcoming technical books. So after 7+ years of writing books, articles, training materials, and presentations on everything from VB to SQL Server to ADO.NET, I've decided to try my hands at a non technical book ... a children's book more specifically.

    What spurred this on? Well, I recently (last week) became a father of my 3rd little girl and if there is one thing I have learned is that they love books. My girls have more books that the local library! Ok, well not that many. But still, they read so much. And it isn't just my kids, I hear my friends, cousins, sisters, neighbors, colleagues and just about everyone talk about how their kids love to read or browse picture books. So my point is that the interest is there for good children's books. But why would I write one? Like many parents, I find myself telling stories and making up silly songs for my kids. The stories appear to be well received by my kids .. I know they are biased, but hey ... why can't I?

    OK, so I decided to write a children's book. I've got the ideas for a few, I just need to find a publisher and an illustrator (I cannot even draw a stick figure correctly). It's not ADO.NET, C# or SQL Server 2005 ... but it may just be the book that stays on someone's bookshelf for years. Wish me luck!

     

More Posts Next page »