none
Valores defecto datarow RRS feed

  • Pregunta


  • Buenos días.

    Trabajo con Visual Studio 2013, VB.NET y SQL Server y tengo una duda relacionada con los valores por defecto a la hora de generar registros en la base de datos. Supongamos que tengo una tabla Artículos con 100 campos y quiero generar un nuevo registro. El código que hago es este:

    Dim Sql As String
            Dim DA As New SqlDataAdapter
            Dim DS As New DataSet
            Sql = "SELECT * FROM Articulos WHERE 1=2"
            DS.Reset()
            DA = New SqlDataAdapter(Sql, Conexion)
            DA.Fill(DS, "Articulos")
    
            Dim RowArt As DataRow = DS.Tables("Articulos").NewRow
    
            RowArt.Item("CodigoArticulo") = "1"
            RowArt.Item("Descripcion") = "PRUEBA"
    
            DS.Tables("Articulos").Rows.Add(RowArt)
            
            Dim Graba As New SqlCommandBuilder(DA)
            DA.Update(DS, "Articulos")
            Graba.Dispose()
         
            DA.Dispose()
            DS.Dispose()

    Este código funciona sin problemas, y si veo el registro en la base de datos los 100 campos tienen el valor por defecto que le puse en el diseño de la tabla, excepto el código y la descripción que le di yo el valor.

    Sin Embargo, la variable RowArt no tiene los valores por defecto de la base de datos, si no que tiene NULL. Por ejemplo, si tengo una columna Precio (suponiendo que sea Decimal con valor por defecto 0) y pongo este mensaje antes del Rows.Add

    MsgBox(RowArt.Item("Precio"))

    no me devuelve 0, si no que tiene el NULL.

    Resumiendo... por razones que no voy a explicar necesitaría que la variable RowArt cogiera todos los valores por defecto que hay en la base de datos, para poder hacer operaciones con ella. ¿existe una manera?

    Espero haberme explicado bien. Un saludo y gracias de antemano



    viernes, 13 de octubre de 2017 12:10

Respuestas

  • "JavierRomero" preguntó:
     
    > ... por razones que no voy a explicar necesitaría que la variable
    > RowArt cogiera todos los valores por defecto que hay en la base de
    > datos, para poder hacer operaciones con ella. ¿existe una manera?

    Sí la hay: leyendo la información de esquema correspondiente a la columna que deseas configurar y aplicándosela al objeto DataColumn correspondiente. Para ello, tan solo necesitas insertar el siguiente procedimiento en tu formulario, clase o módulo:

        ''' <summary>
        ''' Configura el objeto DataColumn especificado con la información
        ''' de esquema de columna existente en el campo correspondiente de
        ''' la tabla de la base de datos.
        ''' </summary>
        ''' <param name="cnn">Objeto SqlConnection abierto.</param>
        ''' <param name="column">Objeto DataColumn correspondiente a la
        ''' columna del objeto DataTable que se desea configurar.</param>
        Friend Shared Sub ConfigurarColumna(cnn As SqlConnection, column As DataColumn)
    
            ' Restricciones de columna para una tabla cualquiera. Si el nombre
            ' de la tabla se encuentra duplicado en la base de datos, en el
            ' segundo elemento hay que especificar el nombre del esquema
            ' propietario de la tabla: "dbo", "sys", "MiEsquema", etc.
            '
            ' Como el nombre de la tabla se toma del valor de la propiedad
            ' TableName del objeto DataTable, dicho valor necesariamente
            ' tendrá que ser igual al nombre de la tabla de la base de datos
            ' a la que pertenece la columna que se desea configurar.
            '
            Dim restricciones As String() = {Nothing, Nothing, column.Table.TableName}
    
            ' El método GetSchema requiere que la conexión se encuentre abierta.
            Dim columns As DataTable = cnn.GetSchema("COLUMNS", restricciones)
    
            ' Seleccionar los datos de esquema de la columna especificada.
            Dim row As DataRow() = columns.Select($"COLUMN_NAME='{column.ColumnName}'")
    
            If (row.Length > 0) Then
                ' Establecer el valor predeterminado de la columna, previa eliminación
                ' de las posibles comillas simples y paréntesis de apertura y cierre
                ' que pudieran existir en el valor por defecto.
                '
                column.DefaultValue = row(0).Item("COLUMN_DEFAULT").ToString().Trim(New Char() {"'"c, "("c, ")"c})
            End If
    
        End Sub

    Lee bien los comentarios que aparecen en el método porque para algo los he escrito. ;-)

    Obviamente, podrías configurar otras propiedades, pero en principio, basta con configurar únicamente el valor de la propiedad DefaultValue del objeto DataColumn.

    > Sql = "SELECT * FROM Articulos WHERE 1=2"

    Y ahora te explico cómo tienes que rellenar un objeto DataTable, sin necesidad de declarar un objeto DataSet y ejecutar la consulta SQL de selección con la clásica condición WHERE 1=2.

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                Using cnn As New SqlConnection(cadena de conexión)
    
                    Dim cmd As SqlCommand = cnn.CreateCommand()
                    cmd.CommandText = "SELECT * FROM Articulos"
                    Dim da As New SqlDataAdapter(cmd)
    
                    Dim dt As New DataTable()
    
                    ' Como se va a recuperar información de esquema en el
                    ' método ConfigurarColumna, la conexión necesariamente
                    ' hay que abrirla, la cual se cerrará y se destruirá
                    ' automáticamente cuando se ejecute su método Dispose.
                    '
                    cnn.Open()
    
                    ' Agregar las columnas necesarias e información sobre
                    ' la clave principal para completar el esquema.
                    '
                    da.MissingSchemaAction = MissingSchemaAction.AddWithKey
    
                    ' En lugar de especificar en la consulta SQL de selección
                    ' la condición WHERE 1=2, u otra cualquiera que haga que
                    ' el resultado sea falso, rellenar el objeto DataTable
                    ' mediante su método FillSchema, el cual nos devolverá un
                    ' conjunto de datos vacío, pero con algunas propiedades
                    ' configuradas, como por ejemplo, AllowDBNull, AutoIncrement,
                    ' MaxLength, ReadOnly y Unique.
                    '
                    da.FillSchema(dt, SchemaType.Source)
    
                    ' Configurar la columna Descripcion.
                    '
                    ConfigurarColumna(cnn, dt.Columns("Descripcion"))
    
                    ' Configurar la columna Precio.
                    '
                    ConfigurarColumna(cnn, dt.Columns("Precio"))
    
                    ' Crear un nuevo objeto DataRow
                    Dim RowArt As DataRow = dt.NewRow
    
                    RowArt.Item("CodigoArticulo") = "1"
                    RowArt.Item("Descripcion") = "PRUEBA"
    
                    dt.Rows.Add(RowArt)
                    DataGridView1.DataSource = dt
    
                    MessageBox.Show(RowArt.Item("Precio").ToString(), "Precio")
    
                    Dim Graba As New SqlCommandBuilder(da)
                    da.Update(dt)
                    Graba.Dispose()
    
                    da.Update(dt)
                    graba.Dispose()
    
                End Using
    
            Catch ex As Exception
                ' Se ha producido un error.
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub

    Nuevamente hago hincapié en la lectura de los comentarios existentes en el código.

    Y como podrás observar en la imagen, la columna Precio toma bien su valor por defecto, el cero:


    Digamos que esto es lo más "sencillo" que puedes hacer para configurar automáticamente las propiedades por defecto de las columnas (no de las filas u objetos DataRow) existentes en el objeto DataTable con aquellos valores que figuran en los correspondientes campos de la tabla de la base de datos.

    Adapta el ejemplo a tus necesidades.

    Método DbDataAdapter.FillSchema (DataTable, SchemaType)

    Un saludo


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.




    domingo, 15 de octubre de 2017 8:45
    Moderador
  • No hay una forma sencilla y eficiente. El Fill no tiene la "inteligencia" necesaria para leer los Default desde la base de datos y pasárselos al DataTable. Y el NewRow lo ejecuta el DataTable, no transmite nada al servidor, por lo que solo puede tener los valores que sea capaz de generar el DataTable.

    En lugar de usar un DataTable sin tipar, podrías usar un DataTable tipado, y configurar los default en el diseño del DataTable. Pero esto es una labor manual, no se trasladan automáticamente desde la base de datos.

    Una chapuza que podrías hacer es salvar la fila después de hacer el newRow, y luego volver a leer la fila que grabaste. Esto no es muy eficiente que digamos, pero por lo menos te traerá los valores predeterminados que el servidor haya cargado en la fila.

    viernes, 13 de octubre de 2017 12:21

Todas las respuestas

  • No hay una forma sencilla y eficiente. El Fill no tiene la "inteligencia" necesaria para leer los Default desde la base de datos y pasárselos al DataTable. Y el NewRow lo ejecuta el DataTable, no transmite nada al servidor, por lo que solo puede tener los valores que sea capaz de generar el DataTable.

    En lugar de usar un DataTable sin tipar, podrías usar un DataTable tipado, y configurar los default en el diseño del DataTable. Pero esto es una labor manual, no se trasladan automáticamente desde la base de datos.

    Una chapuza que podrías hacer es salvar la fila después de hacer el newRow, y luego volver a leer la fila que grabaste. Esto no es muy eficiente que digamos, pero por lo menos te traerá los valores predeterminados que el servidor haya cargado en la fila.

    viernes, 13 de octubre de 2017 12:21
  • "JavierRomero" preguntó:
     
    > ... por razones que no voy a explicar necesitaría que la variable
    > RowArt cogiera todos los valores por defecto que hay en la base de
    > datos, para poder hacer operaciones con ella. ¿existe una manera?

    Sí la hay: leyendo la información de esquema correspondiente a la columna que deseas configurar y aplicándosela al objeto DataColumn correspondiente. Para ello, tan solo necesitas insertar el siguiente procedimiento en tu formulario, clase o módulo:

        ''' <summary>
        ''' Configura el objeto DataColumn especificado con la información
        ''' de esquema de columna existente en el campo correspondiente de
        ''' la tabla de la base de datos.
        ''' </summary>
        ''' <param name="cnn">Objeto SqlConnection abierto.</param>
        ''' <param name="column">Objeto DataColumn correspondiente a la
        ''' columna del objeto DataTable que se desea configurar.</param>
        Friend Shared Sub ConfigurarColumna(cnn As SqlConnection, column As DataColumn)
    
            ' Restricciones de columna para una tabla cualquiera. Si el nombre
            ' de la tabla se encuentra duplicado en la base de datos, en el
            ' segundo elemento hay que especificar el nombre del esquema
            ' propietario de la tabla: "dbo", "sys", "MiEsquema", etc.
            '
            ' Como el nombre de la tabla se toma del valor de la propiedad
            ' TableName del objeto DataTable, dicho valor necesariamente
            ' tendrá que ser igual al nombre de la tabla de la base de datos
            ' a la que pertenece la columna que se desea configurar.
            '
            Dim restricciones As String() = {Nothing, Nothing, column.Table.TableName}
    
            ' El método GetSchema requiere que la conexión se encuentre abierta.
            Dim columns As DataTable = cnn.GetSchema("COLUMNS", restricciones)
    
            ' Seleccionar los datos de esquema de la columna especificada.
            Dim row As DataRow() = columns.Select($"COLUMN_NAME='{column.ColumnName}'")
    
            If (row.Length > 0) Then
                ' Establecer el valor predeterminado de la columna, previa eliminación
                ' de las posibles comillas simples y paréntesis de apertura y cierre
                ' que pudieran existir en el valor por defecto.
                '
                column.DefaultValue = row(0).Item("COLUMN_DEFAULT").ToString().Trim(New Char() {"'"c, "("c, ")"c})
            End If
    
        End Sub

    Lee bien los comentarios que aparecen en el método porque para algo los he escrito. ;-)

    Obviamente, podrías configurar otras propiedades, pero en principio, basta con configurar únicamente el valor de la propiedad DefaultValue del objeto DataColumn.

    > Sql = "SELECT * FROM Articulos WHERE 1=2"

    Y ahora te explico cómo tienes que rellenar un objeto DataTable, sin necesidad de declarar un objeto DataSet y ejecutar la consulta SQL de selección con la clásica condición WHERE 1=2.

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                Using cnn As New SqlConnection(cadena de conexión)
    
                    Dim cmd As SqlCommand = cnn.CreateCommand()
                    cmd.CommandText = "SELECT * FROM Articulos"
                    Dim da As New SqlDataAdapter(cmd)
    
                    Dim dt As New DataTable()
    
                    ' Como se va a recuperar información de esquema en el
                    ' método ConfigurarColumna, la conexión necesariamente
                    ' hay que abrirla, la cual se cerrará y se destruirá
                    ' automáticamente cuando se ejecute su método Dispose.
                    '
                    cnn.Open()
    
                    ' Agregar las columnas necesarias e información sobre
                    ' la clave principal para completar el esquema.
                    '
                    da.MissingSchemaAction = MissingSchemaAction.AddWithKey
    
                    ' En lugar de especificar en la consulta SQL de selección
                    ' la condición WHERE 1=2, u otra cualquiera que haga que
                    ' el resultado sea falso, rellenar el objeto DataTable
                    ' mediante su método FillSchema, el cual nos devolverá un
                    ' conjunto de datos vacío, pero con algunas propiedades
                    ' configuradas, como por ejemplo, AllowDBNull, AutoIncrement,
                    ' MaxLength, ReadOnly y Unique.
                    '
                    da.FillSchema(dt, SchemaType.Source)
    
                    ' Configurar la columna Descripcion.
                    '
                    ConfigurarColumna(cnn, dt.Columns("Descripcion"))
    
                    ' Configurar la columna Precio.
                    '
                    ConfigurarColumna(cnn, dt.Columns("Precio"))
    
                    ' Crear un nuevo objeto DataRow
                    Dim RowArt As DataRow = dt.NewRow
    
                    RowArt.Item("CodigoArticulo") = "1"
                    RowArt.Item("Descripcion") = "PRUEBA"
    
                    dt.Rows.Add(RowArt)
                    DataGridView1.DataSource = dt
    
                    MessageBox.Show(RowArt.Item("Precio").ToString(), "Precio")
    
                    Dim Graba As New SqlCommandBuilder(da)
                    da.Update(dt)
                    Graba.Dispose()
    
                    da.Update(dt)
                    graba.Dispose()
    
                End Using
    
            Catch ex As Exception
                ' Se ha producido un error.
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub

    Nuevamente hago hincapié en la lectura de los comentarios existentes en el código.

    Y como podrás observar en la imagen, la columna Precio toma bien su valor por defecto, el cero:


    Digamos que esto es lo más "sencillo" que puedes hacer para configurar automáticamente las propiedades por defecto de las columnas (no de las filas u objetos DataRow) existentes en el objeto DataTable con aquellos valores que figuran en los correspondientes campos de la tabla de la base de datos.

    Adapta el ejemplo a tus necesidades.

    Método DbDataAdapter.FillSchema (DataTable, SchemaType)

    Un saludo


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.




    domingo, 15 de octubre de 2017 8:45
    Moderador