Click here to Skip to main content
Licence 
First Posted 19 Jul 2004
Views 62,007
Bookmarked 30 times

Inheriting Data Access Layer functions

By | 19 Jul 2004 | Article
Simplify DAL by using Reflection and database table naming conventions

Introduction

There are a number of different ways to program the Data Access Layer (DAL). One way involves dragging data access components onto the IDE and letting visual studio automatically build the SQL. This works fine until you want to change the database from say MS SQL to Oracle, in which case you need to go through all the auto generated SQL strings to change the SQL syntax to run on Oracle. The approach described here is to inherit all the basic SQL functions from one class, then override these functions as necessary. In this way all functions defined in the Table classes and inherited classes can be seen in Intellisense. This makes application building much faster because all the tedious SQL generating code is located in one place leaving the programming of table data access only a question of defining the database table structure.

Using the code

Lets start by looking at how the table DAL class would look like

Public Class Adr_Address
    Inherits DBTable

    Public Structure Address_Type
        Public Address_ID As Integer
        Public Name As String
        Public Address As String
        Public Birthday As DateTime
    End Structure

    Private DBConnStr As String

    Public Sub New(ByVal DBConnStr As String)
        MyBase.New(DBConnStr)
    End Sub
End Class

The Structure Address_Type mirrors the structure of the database table. A variable of type Address_Type is passed to the inherited functions of DBTable. These functions use reflection to determine the names of the table fields and their corresponding value.

Inside the business layer an update to a specific row of Adr_Address can be made as follows

Try
    Dim AddressDB As New Adr_Address(strConn)        
'An instance of the DAL Component dealing with a table called Adr_Address
'strConn contains the connection string
    Dim AddressRow As Adr_Address.Address_Type       
'One Row of the Adr_Address table
    AddressRow.Name = "Nigel"
    AddressRow.Address = "Sunny Switzerland"
    AddressRow.Address_ID = 1

    If Not AddressDB.PutRecord(AddressRow) Then  
       MessageBox.Show("Unable to update address")
    End If

Catch ex As Exception
    MessageBox.Show(ex.Message)
End Try

The class name is the same as the table name Adr_Address. The structure of the table is identical to the structure Address_Type. By passing an object of type Address_Type it is possible for the inherited class DBTable to determine the structure of the UPDATE command.

In the inherited DBTable we know the name of the table because it is the same as the class name. This can be determined by Me.GetType.Name. We receive the definition of the table structure and the updated values in ByRef Row As ValueType. The rest of the code then iteratively goes through this structure to build the SQL statement

Imports System.Reflection
Public Class DBTable
  
   Public Function PutRecord(ByRef Row As ValueType, _
   ByVal RowIndex As Integer) As Boolean
      Dim ErrLoc As String = ClassName + ".PutRecord" 
      Dim SQL As String
      Try
         Dim i As Integer
          Dim Seperator As String = ""
         Dim fields() As FieldInfo
          fields = Row.GetType.GetFields

          REM Build Database query
          SQL = "UPDATE " + ClassName + " SET "
         For i = 0 To fields.Length - 1
            If fields(i).Name <> TableIndex() Then
               Select Case fields(i).FieldType.ToString
                  Case "System.String"
                      If Not fields(i).GetValue(Row) Is Nothing Then
                         SQL &= Seperator & fields(i).Name & " = "
                             SQL &= SQLStringValue(fields(i).GetValue(Row).ToString)
                             Seperator = ","
                         End If
                  Case "System.DateTime"
                         SQL &= Seperator & fields(i).Name & " = "
                      SQL &= SQLDateValue(fields(i).GetValue(Row))
                         Seperator = ","
                     Case "System.Boolean"
                         SQL &= Seperator & fields(i).Name & " = "
                         SQL &= SQLBooleanValue(fields(i).GetValue(Row))
                         Seperator = ","
                     Case "System.Int32"
                      If fields(i).GetValue(Row) <> -1 Then
                             SQL &= Seperator & fields(i).Name & " = "
                             SQL &= " " & CStr(fields(i).GetValue(Row)) & " "
                             Seperator = ","
                         End If
                   End Select
                End If
             Next
               SQL &= "WHERE "
               SQL &= TableIndex() + "= " + RowIndex.ToString + " "
               If ExecuteSQL(SQL) Then
                Return True
             Else
                Return False
             End If
           Catch ex As Exception
               ErrMsg = UnHandledError(ex.ToString(), ErrLoc, SQL)
               Return False
         End Try
   End Function
..
End Class 

In the above code we pass the row of data that we want to update through the parameter ByRef Row As ValueType. The type and value of the data is made by filling the array Fields of type FieldInfo in the line fields = Row.GetType.GetFields. The column name is determined by fields(i).Name, the type by fields(i).FieldType.ToString and the value by fields(i).GetValue(Row).ToString. The database dependent SQL Syntax is made by inherited functions from DBAccess, for example the syntax of date values is dealt with in the inherited function SQLDateValue. This code expects the table to have the following structure.

Table Name <4 characters><Name>
Table Index <Name>_ID

In this case the table index is of type autonumber.

The advantage of this method is that if you have many tables you program the SQL only once. If you require special functions you can override the underlying functions or simply make new ones in the child class. DBTable can be extended to include synchronization, Import/Export, search functions, transaction logging etc. These functions will then be inherited throughout your application. As applications grow and become more complex it is a great advantage to have the SQL centralized.

Improvements

To change the database in this example you need to recompile the code. This could be made at runtime if I where to pass the database type to the DAL. I could then load an assembly corresponding to the database thus making it possible to change the database at runtime. Recently I have been reading about ObjectSpaces. This will probably be the way to go in the future however I believe this will not be shipped with Whidbey.

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

Nigel-Findlater

Software Developer (Senior)

Switzerland Switzerland

Member

I am a VB.NET Software Engineer currently working in a Re Insurance company. My primary interests are Windows Applications, Pocket PC and ASP.NET. I have spent the last 20 years programming, and managing Software Projects.

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
GeneralDe ja vou PinmemberSk8tz2:23 17 Jan '05  
GeneralRe: De ja vou PinmemberNigel-Findlater3:11 17 Jan '05  
GeneralRe: De ja vou PinmemberSk8tz20:57 24 May '05  
Hey Nigel...
 
Sorry about the late comment, but I have to give my 2 cents again..
 
1. Create a value object that can be used in the entire project but without the inherited database functions
The reason is that data structures used in the tables are often passed from object to object
 
Objects are costly with boxing, but it does make sense, best bet here is to inherit the TypeConvertor for the management of the conversions.
##########
 

2. Change the structure to a class
The reason is that Structures are really an old fashioned way of making an object.
 
This is a fine balance, reason being structures are much more faster when iterating through them, I would suggest if you are going the class route make sure its not strongly typed. No use have functionality if not practical, try and find a balance.
##########
 
3. Add a class containing readonly fields and index fields
To cover tables that have not followed the dbtable naming convention
 
Nice one, maybe even calculated/virtual fields that get updated on certain operations based on they attributes( readonly, editable etc..)
##########
 
4. Create interfaces for DBTable, SBSQL and DBAccess
The reason is to be sure that all the functions required by DBTable have been implemented
 
Dont quite understand this one, I would suggest you wrap microsoft database access layers, its highly optomized with plugin functionality and not write your own or use others to quickly.
##########
 

5. During initialization the corresponding database object is used
The reason is that changing the database does not mean recompilation
 
Not sure about this one..
##########
 
6. Find a way to continue using intellesence even when object is being used
The reason is to help continued development of dbtable
 
Totally agrees
##########
 
7. Include dataset orientated updates and inserts
When passing a lot of data from one object to another the dataset is a convenient way of passing information
 
yes, but these must be transparent as well.
##########
 
8. Review naming and use of properties
 
Agree
##########
 
9. Look into using .net sql biulding functions
The reason is that differences in data formats are better done with these built in functions
 
Here I would have a base set of types, then when microsoft database access layer, they can be mapped to the relevant type for the db being used. So the developer doesnt have to worry about the relevant type being supported.
##########
 
More suggestion
---------------
A wizard of some sort to generate the the class for you, Also to keep binding in mind, cause what would be elegant is if you would create a niffty edit control that could bing to the class, and fieldname, and the control behaviour and ui look would adjust in the bind.
 
If you do have the time, This can become quite an exciting DAL, maybe make it open source to start off and see where it goes..

 
Sk8tZ
GeneralStored procedures Pinmembereddie2000au13:59 11 Nov '04  
GeneralRe: Stored procedures PinmemberNigel-Findlater20:01 14 Nov '04  
GeneralRe: Stored procedures Pinmembereddie2000au0:31 15 Nov '04  
GeneralInteresting PinmemberSteven Campbell7:38 20 Jul '04  
GeneralRe: Interesting PinmemberNigel-Findlater21:08 20 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 20 Jul 2004
Article Copyright 2004 by Nigel-Findlater
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid