Click here to Skip to main content
Licence 
First Posted 30 Jun 2004
Views 96,548
Bookmarked 79 times

Wrapper Generator for SQL Server Stored Procedures

By | 30 Jun 2004 | Article
A utility application that generates .NET code for wrapping stored procedures.
 
Part of The SQL Zone sponsored by
See Also

Sample Image - SPGenerator.png

Introduction

I recently became very tired of continuously rewriting the same code over and over again. In my case, it was code to access stored procedures in a SQL Server database. The end result of my frustration is the application presented here.

Background

A search on CodeProject located an article by leppie describing a DBHelper class that he had developed. After test driving the application, I was hooked. Unfortunately, the existing code base did not handle the return value from stored procedures nor did it handle output parameters from the stored procedures. The original article is available here.

I could have used the built in support in Visual Studio and had it generate SqlCommand classes for me. This approach however scatters the database access throughout the application and makes it extremely fragile in the face of changes.

My solution was to use the ideas that I had seen in leppie's article and extend them to handle both return values and output parameters.

Using the application

To use this application, all you have to do is point the application at an existing SQL Server, select the stored procedures that you want wrappers generated for, and hit the lightning bolt. This application and all source code (with the exception of the GetSQL class; for information on it, see this article) are completely free for whatever use you see fit.

Generated Source Code

The generated code provides a single static method on the class that you specify for each stored procedure. The method has the same name as the stored procedure. The sample below is the generated code for a single stored procedure. Using the generated source is as easy as passing in the connection object.

User Code

private void somefunc()
{
   int iRet=0;
   int iNewId=0;
   iRet = heatgmsm_DAL.wl_AddUser(myConn,null,"User",
           "password",false,false, false,true,ref iNewId);
}

Generated Code

namespace heatgmsm
{
using System.Data;
using System.Data.SqlClient;

public class heatgmsm_DAL
{
  private heatgmsm_DAL() //Private since this is never meant to be instaniated
  {
  }

  public static int wl_AddUser(System.Data.SqlClient.SqlConnection connection, 
            System.Data.DataTable table, string uname, string pwd, 
            bool IsUserAdmin, bool IsProviderAdmin, bool IsWaitlistAdmin, 
            bool IsUser, ref int uid)
  {
    int RETURN_VALUE = 0;

    System.Data.SqlClient.SqlCommand cmd = null;
    System.Data.SqlClient.SqlDataReader reader = null;

    if ((connection == null))
    {
      throw new System.ArgumentException("The connection object cannot be null");
    }
    else
    {
      if ((connection.State == System.Data.ConnectionState.Closed))
      {
        connection.Open();
        cmd = new System.Data.SqlClient.SqlCommand("wl_AddUser", 
                                                      connection);
        cmd.CommandType = System.Data.CommandType.StoredProcedure;
        cmd.Parameters.Add("@RETURN_VALUE", 
                                    System.Data.SqlDbType.Int, 0);
        cmd.Parameters["@RETURN_VALUE"].Direction = 
                       System.Data.ParameterDirection.ReturnValue;
        cmd.Parameters["@RETURN_VALUE"].Value = RETURN_VALUE;
        cmd.Parameters.Add("@uname", System.Data.SqlDbType.VarChar, 50);
        cmd.Parameters["@uname"].Direction = 
                             System.Data.ParameterDirection.Input;
        cmd.Parameters["@uname"].Value = uname;
        cmd.Parameters.Add("@pwd", System.Data.SqlDbType.VarChar, 50);
        cmd.Parameters["@pwd"].Direction = System.Data.ParameterDirection.Input;
        cmd.Parameters["@pwd"].Value = pwd;
        cmd.Parameters.Add("@IsUserAdmin", System.Data.SqlDbType.Bit, 0);
        cmd.Parameters["@IsUserAdmin"].Direction = 
                                        System.Data.ParameterDirection.Input;
        cmd.Parameters["@IsUserAdmin"].Value = IsUserAdmin;
        cmd.Parameters.Add("@IsProviderAdmin", System.Data.SqlDbType.Bit, 0);
        cmd.Parameters["@IsProviderAdmin"].Direction = 
                                        System.Data.ParameterDirection.Input;
        cmd.Parameters["@IsProviderAdmin"].Value = IsProviderAdmin;
        cmd.Parameters.Add("@IsWaitlistAdmin", System.Data.SqlDbType.Bit, 0);
        cmd.Parameters["@IsWaitlistAdmin"].Direction = 
                                        System.Data.ParameterDirection.Input;
        cmd.Parameters["@IsWaitlistAdmin"].Value = IsWaitlistAdmin;
        cmd.Parameters.Add("@IsUser", System.Data.SqlDbType.Bit, 0);
        cmd.Parameters["@IsUser"].Direction = 
                                         System.Data.ParameterDirection.Input;
        cmd.Parameters["@IsUser"].Value = IsUser;
        cmd.Parameters.Add("@uid", System.Data.SqlDbType.Int, 0);
        cmd.Parameters["@uid"].Direction = 
                                   System.Data.ParameterDirection.InputOutput;
        cmd.Parameters["@uid"].Value = uid;

        if ((table != null))
        {
          reader = cmd.ExecuteReader();
        }
        else
        {
          cmd.ExecuteNonQuery();
        }

        if (((table != null) && (reader != null)))
        {
          table.Clear();
          table.Columns.Clear();
          for (int i = 0; (i < reader.FieldCount); i = (i + 1))
          {
            System.Type __type;
            string __name;
            __type = reader.GetFieldType(i);
            __name = reader.GetName(i);
            table.Columns.Add(__name, __type);
          }

          for (; reader.Read();)
          {
            System.Data.DataRow row = table.NewRow();
            object[] rowdata = new object[reader.FieldCount];
            reader.GetValues(rowdata);
            row.ItemArray = rowdata;
            table.Rows.Add(row);
          }
          reader.Close();
        }

        // The Parameter @RETURN_VALUE is not an output type
        // The Parameter @uname is not an output type
        // The Parameter @pwd is not an output type
        // The Parameter @IsUserAdmin is not an output type
        // The Parameter @IsProviderAdmin is not an output type
        // The Parameter @IsWaitlistAdmin is not an output type
        // The Parameter @IsUser is not an output type
        uid = ((int)(cmd.Parameters["@uid"].Value));

        connection.Close();

        RETURN_VALUE = ((int)(cmd.Parameters["@RETURN_VALUE"].Value));
        return RETURN_VALUE;
      }
      else
      {
        throw new System.ArgumentException("The connection" + 
           " must be closed when calling this method.");
      }
    }
  }
}
}

As you can see, the amount of code generated, in other words code that you no longer have to write, is quite extensive.

Future Directions

Any and all comments, suggestions, and or feature requests are welcome :).

History

  • July 1st 2004 -- Initial submission.
  • July 1st 2004
    • Updated to use the GetSQL class from the excellent article by Micheal Potter. This allowed me to eliminate the use of my SQLUtils.dll helper library.
    • Added a refresh option to the checked list box context menu.
    • Fixed a bug in the application idle event handler that was causing CPU spikes after items had been selected in the checked list box.
  • July 2nd 2004
    • Fixed a bug pointed out by jobr1ch, namely incorrect method names where generated for stored procedures with spaces in the name. Spaces are now replaced with an underscore character. So, 'Sales By Year' becomes 'Sales_By_Year' instead. Thanks for pointing that out jobr1ch :).
    • Sorted the stored procedures by name.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Charles Horan

Web Developer

Canada Canada

Member

I have been a sofware developer for over 20 years. I first started out developing programs on an old PDP8 in my highschool. Over the years I have seen many changes to our profession. The one constant however has been the need for understanding the problem space at hand. Once you have that understanding the solution space tends to solve itself.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionObjectDatasource PinmemberEdenMachine25:20 21 Nov '06  
GeneralReally suberb Pinmembervivekthangaswamy2:22 26 Oct '05  
GeneralA reliable way Pinmemberchris Liang9:38 30 Aug '05  
GeneralRe: A reliable way - a free one! PinmemberThomas Schittli3:41 28 Sep '05  
Generalgenerated code may be a lot better Pinmembernsimeonov1:32 16 Aug '05  
Generalcalling storedprocedure names having spaces PinmemberNumburisat12:27 14 Mar '05  
Hi
 
The Northwind database has Procedure names with Spaces Ex( Ten Most Expensive Products). How do i call those procedures from Java
 
I have tried the below options
{? = call Northwind.dbo.Ten Most Expensive Products}
{? = call Northwind.dbo.[Ten Most Expensive Products]}
{? = call [Northwind].[dbo].[Ten Most Expensive Products]}
{? = call [Northwind].[dbo].[Ten Most Expensive Products]()}
{? = call [Northwind].[dbo].[Ten_Most_Expensive_Products]}
 
Though i pass the procedure name with spaces still getting error
Exception in thread "main" java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]Could not find stored procedure 'Northwind.dbo.TenMostExpensiveProducts'.
 
Kindly let me know the right way of passing the procedure name to exectue.
 
Thanks
 
Numburisat
GeneralMyGeneration - it's free PinmemberMyGeneration Software5:13 17 Dec '04  
GeneralAdd Windows NT Integrated Security PinmemberBaileyMW7:49 10 Jul '04  
GeneralVery Small Suggestion PinmemberDaaron16:05 8 Jul '04  
GeneralRe: Very Small Suggestion PinmemberCharles Horan16:29 8 Jul '04  
Generalhaha Pinmemberthekilla_1816:34 4 Dec '05  
QuestionIs it really more efficient to build your own DataTables? PinmemberSethMW5:00 8 Jul '04  
AnswerRe: Is it really more efficient to build your own DataTables? PinmemberCharles Horan6:02 8 Jul '04  
Generalsp_helpdb Pinmemberbetterc1:30 7 Jul '04  
GeneralRe: sp_helpdb PinmemberCharles Horan5:17 7 Jul '04  
GeneralHave u think in use DAAB PinmemberBruno Capuano11:42 6 Jul '04  
GeneralAlternative method to populate datatable... PinmemberArjan Einbu21:15 4 Jul '04  
GeneralRe: Alternative method to populate datatable... PinmemberCharles Horan22:33 4 Jul '04  
GeneralRe: Alternative method to populate datatable... PinmemberArjan Einbu2:46 5 Jul '04  
GeneralReturning DataTables PinmemberDanny Crowell19:33 3 Jul '04  
GeneralRe: Returning DataTables PinmemberArjan Einbu21:15 3 Jul '04  
GeneralRe: Returning DataTables PinmemberCharles Horan4:49 4 Jul '04  
Generala few suggestions and a more advanced alternative PinmemberMarc Sommer21:45 2 Jul '04  
GeneralRe: a few suggestions and a more advanced alternative PinmemberCharles Horan4:56 4 Jul '04  
GeneralVery good & a note Pinmemberjobr1ch2:26 2 Jul '04  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120528.1 | Last Updated 1 Jul 2004
Article Copyright 2004 by Charles Horan
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid