Introducción
Este ejemplo nos muestra un Formulario de Pedido usando LINQ, por cuestiones de Documentación, es posible que NO ESTE USANDO CORRECTAMENTE todo el potencial de LINQ, asi que espero sugerencias para mejoras, asi mismo debo decirles que hago un abuso de métodos a nivel de formulario las cuales estarían mejor dentro de clases pero creo que para un inicio esto esta bien y cumple con su objetivo.
Modelo de Base de Datos
Bueno me di la libertad de ponerles el esquema de mi base de datos de pruebas que suelo usar para este tipo de ejemplos.
Obviamente los Tipos de Datos funciones y demas, estan dentro del archivo para descargar, asi que no se preocupen, por cierto me olvidaba, estoy usando Ms SQL Server Express.
Agregando el Objeto LINQ to SQL
Lo primero que debemos hacer es presionar la siguiente combinacion de teclas Ctrl + Shift + A, inmediatamente nos aparecera la siguiente ventana en la cual seleccionaremos la opcion el Elemento LINQ to SQL classes, a la cual le pondremos de nombre "bdVentasLinq.dbml".
A continuación lo que debemos hacer es arrastrar todos Nuestras Tablas de la Base de Datos hacia el Elemento LINQ to SQL, el cual debera quedar de la siguiente forma.
Agregando Clase clsDetalleVenta
A continuacióna gregamos un elemento clase y le damos el nombre de clsDetalleVenta, esta clase nos permitira almacenar el Detalle de un Pedido en especifico.
Public Class clsDetalleVenta
Private idProducto As String
Private nombreProducto As String
Private cantidad As Integer
Private precio As Double
Private subtotal As Double
Private stockArticulo As Double
Public Property _stockArticulo() As Integer
Get
Return stockArticulo
End Get
Set(ByVal value As Integer)
stockArticulo = value
End Set
End Property
Public Property _idProducto() As String
Get
Return idProducto
End Get
Set(ByVal value As String)
idProducto = value
End Set
End Property
Public Property _nombreProducto() As String
Get
Return nombreProducto
End Get
Set(ByVal value As String)
nombreProducto = value
End Set
End Property
Public Property _cantidad() As Integer
Get
Return cantidad
End Get
Set(ByVal value As Integer)
cantidad = value
End Set
End Property
Public Property _precio() As Double
Get
Return precio
End Get
Set(ByVal value As Double)
precio = value
End Set
End Property
Public Property _subtotal() As Double
Get
Return subtotal
End Get
Set(ByVal value As Double)
subtotal = value
End Set
End Property
End Class
Y agregamos un modulo donde metere algunas funciones rutinarias, tales como Cuadros de Dialogo y otras cosas que se me ocurran, a este modulo le pondremos como nombre mensajes.
Module mensajes
Public Sub msginformacion(ByVal mensaje As String)
MessageBox.Show(mensaje, "Sis. Ventas", MessageBoxButtons.OK, _
MessageBoxIcon.Information)
End Sub
Public Sub msgerror(ByVal mensaje As String)
MessageBox.Show("Ocurrio el Error: " & Environment.NewLine _
& mensaje, "Sis. Ventas", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
End Sub
Public Sub msgpregunta(ByVal mensaje As String)
MessageBox.Show(mensaje, "Sis. Ventas", _
MessageBoxButtons.OK, MessageBoxIcon.Question)
End Sub
End Module
Diseñando el Programa
Diseño del Formulario de Busqueda de Clientes
Ya sabemos que debemos presionar Ctrl + Shift + A, y acontinuacion agregamos un elemento Dialog y le ponemos de nombre frmClientes, el cual luego de agregar los siguientes controles.
- 1 DataGridView
- 1 Label
- 1 TextBox
No menciono los 2 Button ya que etos viene por defecto en el Objeto Dialog, luego de agregados los controles deberia quedar algo asi...
Codificando Nuestro Formulario frmClientes
DataContext:
Se encarga de traducir las peticiones de objetos en consultas SQL (ver el esquema de la arquitectura de LINQ) y devolver los resultados como objetos.
Imports System.Windows.Forms
Public Class frmClientes
'Instanciamos un objeto de la clase bdVentasLinqDataContext
Dim bd As New bdVentasLinqDataContext
'Declaro una variable ID de Forma Publica
Public id As String
Private Sub OK_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles OK_Button.Click
'Extraigo el indice del elemento Seleccionado en el DataGridView
Dim row As Integer = Me.DataGridView1.CurrentRow.Index
'Extraigo el elemento situado en la columna DNI_cli
id = Me.DataGridView1.Item("DNI_cli", row).Value.ToString
'Se establece como OK el resultado del Cuadro de Dialogo
Me.DialogResult = System.Windows.Forms.DialogResult.OK
'Cierro el Formulario
Me.Close()
End Sub
Private Sub Cancel_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Cancel_Button.Click
'Se establece como CANCEL el resultado del Cuadro de Dialogo
Me.DialogResult = System.Windows.Forms.DialogResult.Cancel
'Cierro El formulario
Me.Close()
End Sub
Private Sub Dialog1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
'Este codigo usa una consulta LINQ para obtener una secuencia
'para obtener una secuencia IEnumerable de objetos Clientes
Dim query = From cli In bd.Clientes _
Select cli.DNI_cli, cli.ape_cli, cli.nom_cli _
Order By ape_cli Ascending
Me.DataGridView1.DataSource = query.ToList
End Sub
Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles TextBox1.TextChanged
'Este codigo usa una consulta LINQ para obtener una secuencia
'para obtener una secuencia IEnumerable de objetos Clientes
'los cuales concuerden con el texto contenido en la caja de
'texto TextBox1 la cual se concatena con el caracter *
'el que nos proporciona la funcionalidad del % en T-SQL
'Todo esto con la finalidad de ser utilizado con la expresion
'LIKE de nuestra consulta LINQ
Dim cadena As String
cadena = Me.TextBox1.Text & "*"
Dim query = From cli In bd.Clientes _
Where cli.ape_cli Like cadena _
Select cli.DNI_cli, cli.ape_cli, cli.nom_cli _
Order By ape_cli Ascending
'Se asocia como Origen de Datos al DataGridView1
'el resultado de la consulta LINQ
Me.DataGridView1.DataSource = query.ToList
End Sub
End Class
Diseño del Formulario de Busqueda de Productos
Ya sabemos que debemos presioanr Ctrl + Shift + A, y acontinuacion agregamos un elemento Dialog y le ponemos de nombre frmProductos, el cual luego de agregar los siguientes controles.
- 1 DataGridView
- 1 Label
- 1 TextBox
No menciono los 2 Button ya que etos viene por defecto en el Objeto Dialog, luego de agregados los controles deberia quedar algo asi...
Codificando Nuestro Formulario frmClientes
Imports System.Windows.Forms
Public Class frmProductos
'Todo este proceso es muy similar al del Formulario frmCLientes
Dim bd As New bdVentasLinqDataContext
Public id As String
Private Sub OK_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles OK_Button.Click
Dim row As Integer = Me.DataGridView1.CurrentRow.Index
id = Me.DataGridView1.Item("IdArticulo", row).Value.ToString
Me.DialogResult = System.Windows.Forms.DialogResult.OK
Me.Close()
End Sub
Private Sub Cancel_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Cancel_Button.Click
Me.DialogResult = System.Windows.Forms.DialogResult.Cancel
Me.Close()
End Sub
Private Sub frmProductos_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
Dim query = From art In bd.Articulos _
Select art.IdArticulo, art.Modelo, art.pre_arti, art.stock_arti _
Order By Modelo Ascending
Me.DataGridView1.DataSource = query.ToList
End Sub
Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles TextBox1.TextChanged
Dim cadena As String
cadena = Me.TextBox1.Text & "*"
Dim query = From art In bd.Articulos _
Where art.Modelo Like cadena _
Select art.IdArticulo, art.Modelo, art.pre_arti, art.stock_arti _
Order By Modelo Ascending
Me.DataGridView1.DataSource = query.ToList
End Sub
End Class
Diseño del Formulario de Pedidos
Agrgamos un Formulario, al cual le agregaremos los siguientes controles:
- 6 TextBox
- 6 Label
- 1 DataGridView
- 8 Button
Y deberian quedar de la siguiente forma:
Codificando Nuestro Formulario frmClientes
Definimos de Manera Global las Siguientes Variables
'Definir el objeto BD de la clase bdVentasLinqDataContext
Dim bd As New bdVentasLinqDataContext
'Definir un objeto de la clase clsDetalleVenta
Dim objDetVta As clsDetalleVenta
Dim nombreArticulo As String
Dim idArticulo As String
Dim precioArticulo As Double
Dim DNI As String
Dim stockArticulo As Integer
'Definir una LISTA de Objetos clsDetalleVenta
Dim ArrDetVta As New List(Of clsDetalleVenta)
A continuacion codificaremos el Button que se encuentra al lado del TextBox DNI
Private Sub Button1_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button1.Click
'Instanciamos un Objeto del Formulario frmClientes
Dim dialog As New frmClientes
'Mostramos el Formulario
dialog.ShowDialog()
'Si el resultado del Formulario es OK
'----------------------------------------------------
'Si el resultado del Formulario es diferente a OK
'Nos mostrara un mensaje en el que nos indique que no
'hay ningun Cliente Seleccionado
If dialog.DialogResult = Windows.Forms.DialogResult.OK Then
'Usamos una instruccion LINQ para seleccionar a un Cliente en Especifico
'El cual lo recuperamos de la variable ID que fue declarada como PUBLICA
'En el Formulario frmClientes
Dim query = From qCliente In bd.Clientes _
Where qCliente.DNI_cli = dialog.id _
Select qCliente.DNI_cli, qCliente.ape_cli, qCliente.nom_cli
'Cargamos los valores del resultado de la consulta
'LINQ a los TextBox correspondientes
Me.txtDNI.Text = query.ToList.Item(0).DNI_cli.ToString
Me.txtNombre.Text = query.ToList.Item(0).nom_cli & " " & _
query.ToList.Item(0).ape_cli
DNI = query.ToList.Item(0).DNI_cli.ToString
Else
mensajes.msginformacion("No ha seleccionado Ningun Cliente")
Me.txtDNI.Text = ""
Me.txtNombre.Text = ""
DNI = ""
End If
End Sub
Codificaremos el Button que se encuentra al lado del TextBox Nombre del Producto
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button2.Click
'Se Aplica el mismo Procedimiento que en el Evento Anterior
'para seleccionar un Articulo
Dim dialog As New frmProductos
dialog.ShowDialog()
If dialog.DialogResult = Windows.Forms.DialogResult.OK Then
Dim query = From qArti In bd.Articulos _
Where qArti.IdArticulo = dialog.id _
Select qArti.IdArticulo, qArti.Modelo, qArti.pre_arti, qArti.stock_arti
Me.txtNombreProducto.Text = query.ToList.Item(0).Modelo.ToString
Me.txtPrecioProducto.Text = query.ToList.Item(0).pre_arti.ToString("C")
nombreArticulo = query.ToList.Item(0).Modelo.ToString
idArticulo = query.ToList.Item(0).IdArticulo.ToString
precioArticulo = Convert.ToDouble(query.ToList.Item(0).pre_arti.ToString)
stockArticulo = Convert.ToInt32(query.ToList.Item(0).stock_arti.ToString)
txtCantidad.Focus()
Else
mensajes.msginformacion("No ha seleccionado Ningun Producto")
Me.txtNombreProducto.Text = ""
Me.txtPrecioProducto.Text = ""
nombreArticulo = ""
idArticulo = ""
precioArticulo = ""
End If
End Sub
Ahora programaremos el Boton Agregar
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
'Verificamos que el Nombre del Producto, Precio y Cantidad
'NO esten vacios
If txtNombreProducto.Text <> "" And txtPrecioProducto.Text <> "" And txtCantidad.Text <> "" Then
'Verificamos que el Stock del Artículo Seleccionado
'NO sea menor que el solicitado
If Convert.ToInt32(stockArticulo) < Convert.ToInt32(txtCantidad.Text) Then
'Mostramos una Alerta si la verificacion Anterior es Verdadera
mensajes.msginformacion("La Cantidad Requerida es " & _
"Superior a la del Stock")
'Como la Cantidad Solicitada es Mayor a lo que se Tiene en Stock
'Entonces se pregunta si se kiere establecer el STOCk Actual
'Como la nueva cantidad requerida
If MessageBox.Show("Desea Establecer el Stock Actual como la " & _
"Nueva Cantidad Requerida", "Sis. Ventas", _
MessageBoxButtons.YesNo) = _
Windows.Forms.DialogResult.Yes Then
'Establecemos la Nueva Cantidad
txtCantidad.Text = stockArticulo
'Inicializamos el Objeto de la Clase clsDetalleVenta
objDetVta = New clsDetalleVenta
'A continuacion llenamos los valores
'Necesarios para este Objeto
objDetVta._cantidad = Convert.ToInt32(txtCantidad.Text)
objDetVta._idProducto = idArticulo
objDetVta._nombreProducto = nombreArticulo
objDetVta._precio = precioArticulo
objDetVta._stockArticulo = stockArticulo
objDetVta._subtotal = precioArticulo * Convert.ToInt32(txtCantidad.Text)
'En esta parte Verificamos si es que el Aritculo solicitado
'Se encuentra ya en la Lista de Pedidos, de ser Falso
'Lo Agregamos a Nuestros LIST de DetalleVenta
If buscarDetVta(ArrDetVta, objDetVta) = False Then
'Agregamos nuestro Pedido al LIST de DetalleVenta
ArrDetVta.Add(objDetVta)
End If
'Asociamos el LIST de DetalleVenta como origen de
'Datos del DataGridView
Me.DataGridView1.DataSource = ArrDetVta
Else
'Si no se desea establecer el Stock Actual como
'La nueva cantidad a Solicitar se vuelve al Formulario
'Para escoger un Articulo
Button2_Click(Nothing, Nothing)
End If
Else
'Como la Cantidad Requerida es Menor al Stock Actual
'inicializamos el Objeto de la clase clsDetalleVenta
objDetVta = New clsDetalleVenta
'A continuacion llenamos los valores
'Necesarios para este Objeto
objDetVta._cantidad = Convert.ToInt32(txtCantidad.Text)
objDetVta._idProducto = idArticulo
objDetVta._nombreProducto = nombreArticulo
objDetVta._precio = precioArticulo
objDetVta._stockArticulo = stockArticulo
objDetVta._subtotal = precioArticulo * Convert.ToInt32(txtCantidad.Text)
'En esta parte Verificamos si es que el Aritculo solicitado
'Se encuentra ya en la Lista de Pedidos, de ser Falso
'Lo Agregamos a Nuestros LIST de DetalleVenta
If buscarDetVta(ArrDetVta, objDetVta) = False Then
'Agregamos nuestro Pedido al LIST de DetalleVenta
ArrDetVta.Add(objDetVta)
End If
'Asociamos el LIST de DetalleVenta como origen de
'Datos del DataGridView
Me.DataGridView1.DataSource = ArrDetVta.ToList
End If
End If
'Una vez Agregado un Nuevo Detalle para el Pedido
'Limpiamos los textBox
Me.limpiar_producto()
Button2.Focus()
'Calculamos el Total del Pedido
Me.calcular_total()
End Sub
Metodo para veirifcar si es que ya se Solicito un Articulo Anteriomente
Public Function buscarDetVta(ByVal array As List(Of clsDetalleVenta), _
ByVal objDV As clsDetalleVenta) As Boolean
'Funcion para verificar si es que ya se solicito un Articulo
For Each obj As clsDetalleVenta In array
If obj._idProducto = objDV._idProducto Then
Dim nCantidad As Integer
'De encontrarse el Arituclo en la Lista de Pedidos
'Lo que se hace es incrementar la Cnatidad Solicitada
'Mas la cantidad Pedida Anteriormente
nCantidad = obj._cantidad + objDV._cantidad
If nCantidad <= obj._stockArticulo Then
obj._cantidad = nCantidad
obj._subtotal = obj._precio * obj._cantidad
Else
mensajes.msgerror("El Stock Actual es insuficiente para el Requerimiento")
End If
Return True
End If
Next
Return False
End Function
Metodo para Limpiar los TextBox Asociados al Articulo
Sub limpiar_producto()
'Metodo para limpiasr TextBox
Me.txtCantidad.Clear()
Me.txtNombreProducto.Clear()
Me.txtPrecioProducto.Clear()
End Sub
Metodo para Calcular el Total del Pedido
Sub calcular_total()
'Metodo para Calcular El Total del Pedido
Dim sum As Double
For Each i As clsDetalleVenta In ArrDetVta
sum += i._subtotal
Next
Me.txtTotal.Text = sum.ToString("C")
End Sub
Ahora Programaremos el Boton Eliminar
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button4.Click
'Removemos un Articulo seleccionado en el DataGridView
ArrDetVta.RemoveAt(Me.DataGridView1.CurrentRow.Index)
'Vovlemos a Asociar nuestro LIST como origen de Datos del DataGridView
Me.DataGridView1.DataSource = ArrDetVta.ToList
'Volvemos a Calcular el Total del Pedido
Me.calcular_total()
End Sub
Programamos el Boton Cancelar
Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button5.Click
limpiar_cliente()
limpiar_producto()
limpiar_venta()
Me.calcular_total()
End Sub
Metodo para limpiar los Controles asociados al Cliente
Sub limpiar_cliente()
'Metodo para limpiar los textBox Asociados al Cliente
Me.txtDNI.Clear()
Me.txtNombre.Clear()
End Sub
Metodo para borrar el Detalle del Pedido
Sub limpiar_venta()
'Limpiamos el LIST usando su Metodo CLEAR
ArrDetVta.Clear()
'Vovlemos a Asociar nuestro LIST como origen de Datos del DataGridView
Me.DataGridView1.DataSource = ArrDetVta.ToList
End Sub
Y por Ultimo y quizas lo mas importante, la codificacion del Boton Grabar
Private Sub btngrabar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles btngrabar.Click
'Aprovechando que nuestra Base de Datos
'Esta relacionada, usaremos a LINQ para que
'Nos haga las Inserciones y actualizaciones
'Que necesitamos
Try
'La siguiente Expresion me devuelve un Objeto Cliente
'buscandolo por su id es decir por el Campo DNI_Cli
Dim C As Cliente = bd.Clientes.Single(Function(p) p.DNI_cli = Me.txtDNI.Text)
'Creo un nuevo Encabezado de Boleta
'Y procedo a Inicializarlo
'-------------------------------------------------
Dim EB As New EncabezadoBoleta
EB.Fech_Bol = Date.Now
EB.Total_Bol = CDec(Me.txtTotal.Text)
EB.Anulado = "F"
EB.Cliente = C
EB.IdCliente = C.IdCliente
'--------------------------------------------------
'
'
'Ya que tengo todo el Detalle del Pedido en un LIST
'Aprovechare este detalle para generar mis Objetos Pedido
For Each obj As clsDetalleVenta In ArrDetVta
'Instacion un Objeto Articulo Seleccionandolo
'Por el Campo IdArticulo
Dim Art As Articulo = _
bd.Articulos.Single(Function(a) a.IdArticulo = obj._idProducto.ToString())
'Creo un nuevo Detalle de Boleta
'Y procedo a Inicializarlo
Dim DB As New DetalleBoleta
DB.Articulo = Art
DB.Cant_det = obj._cantidad
DB.Importe = obj._subtotal
DB.Prec_det = obj._precio
'Agrego el Detalle de Boleta a mi Encabezado de Boleta
EB.DetalleBoletas.Add(DB)
Next
'Aqui Actualizo la Base De Datos con el Metodo SubmitChanges
bd.SubmitChanges()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Conclusiones
Como vemos, el modelo de programación que hemos usado para hacer todo esto es realmente limpio y orientado a objetos.
Espacios de nombres usados en el código de este artículo:
System.Data
System.Linq
System.Xml.Linq
Posted by Fredy Najarro
on 14:13