A downloadable file for this article is available here.
The entire source code for this article is available in the form of downloadable zip. The solution was developed using Microsoft Visual Studio 2003 Enterprise Architect with Microsoft SQL Server 2005 Developer Edition on Microsoft Windows Server 2003 Enterprise Edition. Even though I believe that the source code available with this contribution can work with Microsoft Visual Studio.NET 2002, I didn't really test it in any other environment. I request that you post in the discussion area if you have any problems with execution.
What exactly is this DML support class doing?
In several applications, we use DML statements which execute dynamically. If we are working with an INSERT statement that has too many columns, it would be rather daunting. The same would be true for an UPDATE statement with many columns.
To solve all these issues, I developed a simple wrapper class specifically to work with DML statements flexibly. As part of what was needed, I declared the following enumerations:
When we work with a DML statement, it would be generally an INSERT, UPDATE or DELETE (putting SELECT aside). DELETE is very simple and I simply don't want to handle it in this class. That is why I declared only "Insert" and "Update" as part of the "Command Type."
When working with DML commands, the syntax will be different based on the data types. To support different data types, I declared the above enumeration.
To execute the DML command, I am using the Data Helper class developed by me in my previous articles. If you want to include your own code, I request that you go ahead by forgetting the data helper code. You can also modify this class with respect to Microsoft Data Access Blocks.
Private m_SQL AsString = "" Private m_dbObject AsObject = Nothing'this should be either 'WebLib' or 'WinLib' objects Private m_ColNameList AsString = "" Private m_ColValList AsString = "" Private m_CommandType As CommandType 'only for storing files directly in database Private m_FileColNames() AsString = Nothing'to hold all column names to which files are to be uploaded Private m_FileByteArrays() AsObject = Nothing'the content of each file to be uploaded..
PublicSubNew(ByVal DMLCommandType As CommandType, ByRef dbObject AsObject) 'dbObject should be either 'WebLib' or 'WinLib' objects If dbObject IsNothingThen ThrowNew Exception("DBLib Object is currently nothing") EndIf m_dbObject = dbObject m_CommandType = DMLCommandType SelectCase DMLCommandType Case CommandType.Insert m_SQL = "INSERT INTO " Case CommandType.Update m_SQL = "UPDATE " EndSelect EndSub
The above code contains the constructor, which accepts two parameters. The first is "CommandType" and the second is the "database" object. Based on the command type, I initially started with the command itself.
To provide the table name, I created the following property:
PublicWriteOnlyProperty TableName() Set(ByVal Value) SelectCase m_CommandType Case CommandType.Insert m_SQL &= Value & " () VALUES ()" Case CommandType.Update m_SQL &= Value & " SET " EndSelect EndSet EndProperty
The following is the code necessary for adding a column (of type binary) to the INSERT command.
PublicSub addFileColumn(ByVal ColName AsString, ByRef UpFile As System.Web.HttpPostedFile) 'make sure to include this attribute in your form tag b4 using this method ...enctype="multipart/form-data" 'change the value according to datatype Dim FileStream As System.IO.Stream SelectCase m_CommandType Case CommandType.Insert 'INSERT command SelectCase m_dbObject.ConnectionType Case DBConnType.MSSQL 'copy the same below in UPDATE case also Dim fileLength AsInteger = UpFile.ContentLength If (fileLength = 0) Then ThrowNew Exception("No information is available in selected File..try giving another existing filename") EndIf Dim FileByteArray(fileLength) AsByte FileStream = UpFile.InputStream FileStream.Read(FileByteArray, 0, fileLength) 'append this information to already existing arrays If m_FileColNames IsNothingThen ReDim m_FileColNames(0) ReDim m_FileByteArrays(0) Else ReDimPreserve m_FileColNames(UBound(m_FileColNames) + 1) ReDimPreserve m_FileByteArrays(UBound(m_FileByteArrays) + 1) EndIf m_FileColNames(m_FileColNames.Length - 1) = ColName m_FileByteArrays(m_FileByteArrays.Length - 1) = FileByteArray CaseElse ThrowNew Exception("currently this library supports only SQL.NET Provider to upload files") EndSelect m_ColNameList = IIf(m_ColNameList = "", ColName, m_ColNameList & "," & ColName) m_ColValList = IIf(m_ColValList = "", "@" & Trim(ColName), m_ColValList & ",@" & Trim(ColName)) 'this is for oledb type 'm_ColValList = IIf(m_ColValList = "", "?", m_ColValList & ",?")
The following is the code necessary for adding a column (of type binary) to the UPDATE command.
CaseCommandType.Update 'UPDATE command SelectCase m_dbObject.ConnectionType Case DBConnType.MSSQL m_SQL &= ColName & "=" & "@" & ColName & "," 'the following is same as the above case Dim fileLength AsInteger = pFile.ContentLength If (fileLength = 0) Then ThrowNew Exception("No information is available in selected File..try giving another existing filename") EndIf Dim FileByteArray(fileLength) AsByte FileStream = UpFile.InputStream FileStream.Read(FileByteArray, 0, fileLength) 'append this information to already existing arrays If m_FileColNames IsNothingThen ReDim m_FileColNames(0) ReDim m_FileByteArrays(0) Else ReDimPreserve m_FileColNames(UBound(m_FileColNames) + 1) ReDimPreserve m_FileByteArrays(UBound(m_FileByteArrays) + 1) EndIf m_FileColNames(m_FileColNames.Length - 1) = ColName m_FileByteArrays(m_FileByteArrays.Length - 1) = FileByteArray CaseElse ThrowNew Exception("currently this library supports only SQL.NET Provider to upload files") EndSelect EndSelect
Once the DML command is framed, we need to execute it with a separate method. The method looks something like the following:
PublicSub ExecuteCommand() If m_FileColNames IsNothingThen'if no images exist in the command m_dbObject.SQLExecute(Me.GeneratedSQLCommand) Else'insert images as well m_dbObject.SQLExecute(Me.GeneratedSQLCommand, m_FileColNames, m_FileByteArrays) EndIf EndSub
The above method works with another method called "GeneratedSQLCommand," which is defined as follows:
PublicReadOnlyProperty GeneratedSQLCommand() Get SelectCase m_CommandType Case CommandType.Insert m_SQL = Replace(m_SQL, "()", "(" & m_ColNameList & ")", , 1) m_SQL = Replace(m_SQL, "()", "(" & m_ColValList & ")") Case CommandType.Update If InStr(m_SQL, " WHERE ") = 0 Then Return Left(m_SQL, Len(m_SQL) - 1) EndIf EndSelect Return m_SQL EndGet EndProperty
The method "ExecuteCommand" executes the DML command with the help of my data helper class provided in my previous articles. You can embed your own logic to execute the DML command at that point.
If you wanted to clear the existing DML command frame, you can use the above command. It is mainly used when you want to reuse the same DML object several times.
Working with the above class is as simple as the following code:
Dim ins AsNew DMLLib(DMLLib.CommandType.Insert, db) With ins .TableName = "emp" .addColumn("empno", "1001") .addColumn("ename", "jag") .ExecuteCommand() EndWith
If necessary, you can even put "addColumn" in a loop to work with a larger number of columns. The only important issue is that the "TableName" must be the first assignment to the DMLLib object.
Any feedback, suggestions, bugs, errors, improvements etc., are highly appreciated at jag_chat@yahoo.com.