ARTICLE

Generate SQL statements with objects, attributes and reflection

Posted by Edmund H Smith Articles | VB.NET Articles April 25, 2008
This article tells you about how to create a sql command with sql statement and parameters dynamically.
 
Reader Level:

Introduction

Many developers hate one thing about software development, writing SQL Statements. SQL is a language on its own and it is ubiquitous in today's development environment. When there are changes made to the tables, we have to modify the affected SQL statements, be it in the application codes or in Stored Procedures.

Would it be good if we do not have to write or modify SQL statements, just modify some VB codes, compile and Voila, your application is good to go.

Can it be done?

Sure.

How?

We will be using Attributes that can be used on your objects to map the properties to a Database Table Column. And we will look into  Reflection classes to help us to create a simple SELECT Statement Command dynamically, with parameters and values assigned to the parameters.

Attributes

During development, we may have used attributes in our codes, one of the most commonly used attributes is the WebMethod attributes to expose methods in a web service. And who can forget about DllImport when calling Windows API.

For this solution, we will need to create a custom attribute object. To do that, we have to create a class and inherit the Attribute class.

Public Class DAOAttribute

    Inherits System.Attribute

    Public Sub New()

        MyBase.New()

    End Sub

End Class

 

For this class, we need to declare 3 variables and exposed it through properties.

 

Private _DatabaseColumn As String

Private _ValueType As Type

Private _PrimaryKey As Boolean

 

Public Property DatabaseColumn() As String

    Get

        Return Me._DatabaseColumn

    End Get

    Set(ByVal value As String)

        _DatabaseColumn = value

    End Set

End Property

 

Public Property ValueType() As Type

    Get

        Return Me._ValueType

    End Get

    Set(ByVal value As Type)

        _ValueType = value

    End Set

End Property

 

Public Property PrimaryKey() As Boolean

    Get

        Return Me._PrimaryKey

    End Get

    Set(ByVal value As Boolean)

        _PrimaryKey = value

    End Set

End Property

 

  1. _DatabaseColumn, this variable stores the database Column name
  2. _ValueType, this variable represents the Value Type
  3. _PrimaryKey, indicates if the Database Column is a primary key

Next, we need to modify the Constructor to initialize the 3 variables

Public Sub New(ByVal databaseColumn As String, ByVal valueType As Type, ByVal primaryKey As Boolean)

    MyBase.New()

    _DatabaseColumn = databaseColumn

    _ValueType = valueType

    _PrimaryKey = primaryKey

End Sub

 
And we are ready to get to the next level.

Implementing the Attribute

Below is the code for the object that I will be using for this example

Public Class Customer

    Private _CustomerFirstName As String

    Private _CustomerLastName As String

    Private _CustomerIDNumber As String

 

    Public Sub New()

        _CustomerFirstName = ""

        _CustomerLastName = ""

        _CustomerIDNumber = ""

    End Sub

 

    Public Property CustomerFirstName() As String

        Get

            Return _CustomerFirstName

        End Get

 

        Set(ByVal value As String)

            _CustomerFirstName = value

        End Set

    End Property

 

    Public Property CustomerLastName() As String

        Get

            Return _CustomerLastName

        End Get

 

        Set(ByVal value As String)

            _CustomerLastName = value

        End Set

    End Property

 

    Public Property CustomerIDNumber() As String

        Get

            Return _CustomerIDNumber

        End Get

 

        Set(ByVal value As String)

            _CustomerIDNumber = value

        End Set

    End Property

End Class

Assume you have an existing customer object that you want to generate SQL statement from. All you need now is to add in the attributes to the Get function of each property. Why put it at the GET function? This is because we will be using Reflection to extract the value. We will come to the Reflection Part later.

Below are the codes, you noticed that I set the Primary Key to True for CustomerIDNumber. This means that I have determined that the Customer ID number in the database is the Primary Key. You can determine your own Primary Key(s) , it is advisable to follow the relevant Database Table that the object is representing. If there are no Primary Keys set for the Database Table, you can determine your own for this object.

Public Property CustomerFirstName() As String

 

    <DAO("FirstName", GetType(String), False)> _

    Get

        Return _CustomerFirstName

    End Get

 

    Set(ByVal value As String)

        _CustomerFirstName = value

    End Set

End Property

Public Property CustomerLastName() As String

 

 

    <DAO("LastName", GetType(String), False)> _

    Get

        Return _CustomerLastName

    End Get

 

    Set(ByVal value As String)

        _CustomerLastName = value

    End Set

End Property

Public Property CustomerIDNumber() As String

 

 

    <DAO("CustID", GetType(String), True)> _

    Get

        Return _CustomerIDNumber

    End Get

 

    Set(ByVal value As String)

        _CustomerIDNumber = value

    End Set

End Property

Executing it with Reflection

To retrieve the attributes from the object, we have to go deeper into the .NET framework. We are going to use classes in the Reflection namespace to extract the attribute details from the Customer object.  Below are the codes to create a generic DbCommand object with a Select Statement with Parameters in place.

Private Function CreateSelectCommand(ByVal dataObject As Object, ByVal factory As DbProviderFactory, ByVal TableName As String) As DbCommand

    Dim t As Type = dataObject.[GetType]()

    Dim dao As DAOAttribute

    Dim cmd As DbCommand = factory.CreateCommand()

    Dim param As DbParameter

 

    Dim Fields As New StringCollection()

    Dim sbWhere As New StringBuilder(" WHERE ")

    Dim HasCondition As Boolean = False

    'Indicates that there is a WHERE Condition

    For Each mi As System.Reflection.MethodInfo In t.GetMethods()

        'Go thru each method of the object

        For Each att As Attribute In Attribute.GetCustomAttributes(mi)

            'Go thru the attributes for the method

            If GetType(DAOAttribute).IsAssignableFrom(att.[GetType]()) Then

                'Checks that the Attribute is of the right type

                dao = DirectCast(att, DAOAttribute)

                Fields.Add(dao.FieldName)

                'Append the Fields

                If dao.PrimaryKey Then

                    'Append the Conditions

                    If HasCondition Then

                        sbWhere.Append(" AND ")

                    End If

                    sbWhere.AppendFormat("{0} = @{0}", dao.FieldName)

                    param = factory.CreateParameter()

                    param.ParameterName = "@" + dao.FieldName

 

                    If cmd.Parameters.IndexOf(param.ParameterName) = 0 Then

                        param.DbType = DirectCast([Enum].Parse(GetType(DbType), dao.ValueType.Name), DbType)

                        cmd.Parameters.Add(param)

                        param.Value = mi.Invoke(obj, Nothing)

                    End If

 

                    'Set the HasCondition flag to true

                    HasCondition = True

                End If

            End If

        Next

    Next

 

    Dim arrField As String() = New String(Fields.Count - 1) {}

    Fields.CopyTo(arrField, 0)

    cmd.CommandText = "SELECT " + String.Join(",", arrField) + " FROM " + TableName + (IIf(HasCondition, sbWhere.ToString(), " "))

    Return cmd

End Function

Beyond Select Statements

This is a very practical example of using Attributes and Reflection. You may even create your own Insert Statement Commands with these codes. And also you may want to extend the DAOAttribute object to cater to your requirements.

Besides generating SQL statements, there are a lot of cool stuff that you can do with Attributes and Reflection, you can even create your own XML Attributes and Formatter for the classes you created!!!

NOTE: THIS ARTICLE IS CONVERTED FROM C# TO VB.NET USING A CONVERSION TOOL. ORIGINAL ARTICLE CAN BE FOUND ON C# Corner (http://www.c-sharpcorner.com/).

Login to add your contents and source code to this article
share this article :
post comment
 
6 Months Free & No Setup Fees ASP.NET Hosting!
Become a Sponsor
PREMIUM SPONSORS
  • Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon. Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees. As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
    The leading .NET charting control now features PDF, Flash and Silverlight export, visualization of large datasets and more. Deliver true charting functionality to your BI, Scorecard, Presentation or Scientific apps. Download evaluation now.
6 Months Free & No Setup Fees ASP.NET Hosting!
Become a Sponsor