Colabora |
Generador de código DML para SQLUtilidad para Generar el código DML necesario para las acciones sobre tablas de SQL Server.
Fecha: 15/Dic/2007 (15-12-07)
|
IntroducciónEn pocas palabras, esta utilidad sirve para "como su nombre lo dice…" generar el código DML (Data Manipulation Language) necesario para ejecutar las acciones típicas sobre una tabla en SQL Server 2000 tales como SELECT, INSERT, UPDATE o DELETE. Digo SQL Server 2000 porque es la única versión de SQL en la que he probado. Es posible que también funcione para SQL Server 7 pero no lo aseguro. Una peque reseñaEn primer lugar saludos a todos quienes visitan esta estupenda Web, esta es la segunda vez que colaboro aquí, cierta ves lo hice como hace 4 años con un reproductor de mp3, pero en fin eso ya es historia. Bueno, hace mucho tiempo desde que empecé con este lió de desarrollar aplicaciones que trabajan con datos me dí cuenta que era muy tedioso eso de ir escribiendo todo el código para realizar un simple select, insert, update o delete, sobretodo si la tabla con la que estaba trabajando tenía como 30 campos, entonces empecé a preguntarme en mis adentros muy adentros… ¿habrá alguna forma de evitarme todos eso y que se me genere solito el código tan solo con decir que tipo de acción quiero ejecutar sobre cierta tabla? "y estoy seguro que no soy el único que se preguntó eso". Para buscar respuestas me dirigí al famosísimo y muy conocido Google, el que todo lo sabe, pero nunca encontré algo parecido "puede ser que sí lo haya pero no lo he encontrado", así que no me quedó de otra que hacerlo yo mismo. El trabajo fue duro pero el fin lo recompensa. El resultado es una clase que primero la hice para una aplicación desarrollada en Visual Basic 6.0 y funcionó de maravilla y ahora con esto de las nuevas tecnologías y en vista que necesito lo mismo para mis nuevas aplicaciones con .NET, la transformé a VB.NET El código:Bueno, sin más palabras, les presento a continuación el código de la Super Clase: Option Strict Off Imports System.Data.SqlClient ''' <summary> ''' Encapsula métodos necesarios para obtener información ''' interna de tablas de SQL Server. ''' </summary> ''' <remarks>Victor Viscarra © 2007</remarks> Public Class CN_SQL Private cs As String Public Enum SQLTYPE eSelect eInsert eUpdate eDelete End Enum Public Sub New(ByVal CadenaConexion As String) cs = CadenaConexion End Sub ''' <summary> ''' Obtiene la lista de campos que contiene una tabla. ''' </summary> ''' <param name=Tabla">Nombre de la tabla.</param>" Private Function GetListaCampos(ByVal Tabla As String) As DataTable Dim dt As New DataTable Dim sql As String Dim cpk As Integer sql = "select a.name as Nombre, cast(a.colorder as int) as Orden," sql += " cast(b.name as varchar) as Tipo," sql += " Length = " sql += " case" sql += " when b.name = 'char' or b.name = 'varchar' then cast(a.length as int)" sql += " else cast(a.xprec as int)" sql += " end," sql += "'' as Descripcion, 0 as isPK, a.isNullable," sql += " isIdentity = " sql += " case" sql += " when a.autoval is null then 0" sql += " else 1" sql += " end" sql += " from syscolumns a inner join systypes b" sql += " on (a.xtype = b.xtype and a.xusertype = b.xusertype)" sql += " where a.id = (object_id(N'[dbo].[{0}]'))" sql += " order by colorder" sql = String.Format(sql, Tabla) Try Dim da As New SqlDataAdapter(sql, cs) da.Fill(dt) ' Llena los datos de descripción y primary key. If Not dt Is Nothing Then For Each dr As DataRow In dt.Rows dr("Descripcion") = Me.GetDesCampo(Tabla, dr("Nombre").ToString) dr("isPK") = Me.IsPKCampo(Tabla, dr("Nombre").ToString) If CInt(dr("isPK")) = 1 Then cpk += 1 Next End If Catch ex As Exception Throw ex End Try Return dt End Function ''' <summary> ''' Obtiene la descripción de un campo de la Base de Datos. ''' </summary> ''' <param name=Tabla">Nombre de la tabla propietaria del campo</param>" ''' <param name=Campo">Campo del que se quiere obtener la descripción</param>" Private Function GetDesCampo(ByVal Tabla As String, ByVal Campo As String) As String Dim sql As String Dim ret As String = Nothing Dim o As Object Dim cn As New SqlConnection(cs) sql = "select value from ::fn_listextendedproperty ('MS_Description','user','dbo','table'," sql += "'{0}','column','{1}')" sql = String.Format(sql, Tabla, Campo) Try Dim cm As New SqlCommand cn.Open() With cm .Connection = cn .CommandType = CommandType.Text .CommandText = sql .ExecuteNonQuery() o = .ExecuteScalar() End With If Not o Is Nothing Then ret = o.ToString() End If Catch ex As Exception If TypeOf ex Is InvalidCastException Then ret = Nothing Else Throw ex End If Finally If cn.State <> ConnectionState.Open Then cn.Close() End If cn.Dispose() End Try Return ret End Function ''' <summary> ''' Obtiene un valor que indica si un campo forma parte del Primary Key ''' de la tabla de acuerdo al parámetro pasado. ''' </summary> ''' <param name=Tabla">Nombre de la tabla propietaria del campo</param>" ''' <param name=Campo">Campo del que se quiere obtener la información</param>" Private Function IsPKCampo(ByVal Tabla As String, ByVal Campo As String) As Integer Dim ret As Integer Dim c As String = String.Empty Dim sql As String Dim o As Object Dim cn As New SqlConnection(cs) sql = "select 'T' from sysindexkeys ik, sysindexes i" sql += " Where ik.id = i.id" sql += " and ik.indid = i.IndId" sql += " and ik.colid = (select colid from syscolumns" sql += " where id = (object_id(N'[dbo].[{0}]'))" sql += " and name = '{1}')" sql += " and i.id = (object_id(N'[dbo].[{0}]'))" sql += " and i.name in (SELECT name" sql += " From sysobjects" sql += " where (xtype = 'PK'))" sql = String.Format(sql, Tabla, Campo) Try Dim cm As New SqlCommand cn.Open() With cm .Connection = cn .CommandType = CommandType.Text .CommandText = sql o = .ExecuteScalar() End With If Not o Is Nothing Then c = o.ToString() End If If c = "T" Then ret = 1 Catch ex As Exception If TypeOf ex Is InvalidCastException Then ret = 0 Else Throw ex End If Finally If cn.State <> ConnectionState.Open Then cn.Close() End If cn.Dispose() End Try Return ret End Function ''' <summary> ''' Genera una Sentencia SQL (DML) de acuerdo al nombre de la tabla y tipo ''' que se desee. ''' </summary> ''' <param name=Tabla">Nombre de la tabla</param>" ''' <param name=TipoDML">Tipo de DML que se quiere obtener</param>" Public Function GeneraSQL(ByVal Tabla As String, ByVal TipoDML As SQLTYPE) As String Dim i, controlPK, fc As Integer Dim sql As String = String.Empty Dim sql2 As String Dim dt As DataTable ' Obtiene todos los datos necesarios de cada ' campo existente de la tabla Try dt = Me.GetListaCampos(Tabla) Catch ex As Exception dt = Nothing Throw ex End Try If Not dt Is Nothing Then fc = dt.Rows.Count - 1 Select Case TipoDML Case SQLTYPE.eSelect ' Genera la cadena SQL <<Select>> sql = "SELECT " For Each dr As DataRow In dt.Rows sql += dr("Nombre") If i < fc Then sql += ", " i += 1 Else sql += vbCrLf + "FROM {0}" End If Next Case SQLTYPE.eInsert ' Genera la cadena SQL <<Insert Into>> sql = "INSERT INTO {0}" + vbCrLf + " (" sql2 = "VALUES" + vbCrLf + " (" For Each dr As DataRow In dt.Rows If dr("isIdentity") = 0 Then sql += dr("Nombre") sql2 += "@" + dr("Nombre") If i < fc Then sql += ", " sql2 += ", " Else sql += ")" sql2 += ")" sql += vbCrLf + sql2 End If End If i += 1 Next Case SQLTYPE.eUpdate ' Genera la cadena SQL <<Update>> sql = "UPDATE {0}" + vbCrLf + "SET " controlPK = 0 For Each dr As DataRow In dt.Rows If dr("isPK") = 0 Then controlPK += 1 sql += dr("Nombre") + " = @" + dr("Nombre") If i < fc Then sql += ", " + vbCrLf Else sql += vbCrLf + "WHERE " End If End If i += 1 Next If controlPK = 0 Then sql = "NO SE PUEDE GENERAR EL COMANDO UPDATE PARA LA TABLA {0}" sql += " DEBIDO A QUE NO POSEE CAMPOS ACTUALIZABLES." sql = String.Format(sql, Tabla) Throw New Exception(sql) End If controlPK = 0 i = 0 For Each dr As DataRow In dt.Rows If CInt(dr("isPK")) = 1 Then controlPK += 1 sql += dr("Nombre") + " = @" + dr("Nombre") sql += vbCrLf + " AND " End If Next If controlPK = 0 Then sql = "NO SE PUEDE GENERAR EL COMANDO UPDATE PARA LA TABLA {0}" sql += " DEBIDO A QUE NO POSEE PRIMARY KEY." sql = String.Format(sql, Tabla) Throw New Exception(sql) Exit Select End If sql = sql.Substring(0, sql.Length - 7) Case SQLTYPE.eDelete ' Genera la cadena SQL <<Delete>> sql = "DELETE FROM {0}" sql += vbCrLf + "WHERE " controlPK = 0 For Each dr As DataRow In dt.Rows If CInt(dr("isPK")) = 1 Then controlPK += 1 sql += dr("Nombre") + " = @" + dr("Nombre") sql += vbCrLf + " AND " End If Next If controlPK = 0 Then sql = "NO SE PUEDE GENERAR EL COMANDO UPDATE PARA LA TABLA {0}" sql += " DEBIDO A QUE NO POSEE PRIMARY KEY." sql = String.Format(sql, Tabla) Throw New Exception(sql) Exit Select End If sql = sql.Substring(0, sql.Length - 7) End Select If Not String.IsNullOrEmpty(sql) Then sql = String.Format(sql, Tabla) End If End If Return sql End Function End Class
Si revisamos un poco el código nos damos cuenta de que la clase se divide en cuatro funciones:
Nota:
Espero que les sirva de mucho y que le saquen el jugo a la clase. Y ya saben, cualquier duda o comentario... 1800-AUXILIO, o me lo escriben por correo. Hasta una próxima Colaboración. Espacios de nombres usados en el código de este artículo:System.Data System.Data.SqlClient
|
Código de ejemplo (comprimido): |
Fichero con el código de ejemplo:
ViperNET_Generador_de_Codigo_DML_para_SQL.zip - 45.0 KB
|