Introducción
Este articulo intenta brindar un ejemplo practico de como hacer uso de los objetos de ADO.NET para poder manipular la información de la base de datos, en este caso será de Ms Access.
Gran parte de la explicación se ha realizado en artículos previos
C# – ADO.NET – Parte 3 – Actualización Información Sql Server
que si bien tratan otra base de datos, se vera que salvo algunos pequeños detalles es prácticamente idéntico.
Es por eso que a medida que se vaya analizando el código del articulo es recomendable darle un vistazo al link de la Parte 3 del articulo, este contendrá detalles mas precisos sobre algunos aspectos utilizados.
1 – Creación nueva entidad (Insert)
En este código encontraran también el método Save() el cual será el encargado de determinar si es necesario insertar el registro o simplemente actualizarlos
public static ContactoEntity Save(ContactoEntity contacto) { if (string.IsNullOrEmpty(contacto.Nombre)) throw new BusinessException(Messages.MSG1002); if (string.IsNullOrEmpty(contacto.Apellido)) throw new BusinessException(Messages.MSG1003); if (Exists(contacto)) return Update(contacto); else return Insert(contacto); }
Si se analiza el código veras que la funcionalidad que determina si existe la entidad es idéntica a como se programaría cuando se hace uso de Sql Server, el único cambio radica en que se utiliza los objeto de OleDb
private static bool Exists(ContactoEntity contacto) { if (contacto == null) throw new BusinessException(Messages.ERR1001); return Exists(contacto.IdContacto); } private static bool Exists(int Id) { string sql = @"SELECT COUNT(*) FROM Contacto WHERE IdContacto = @Id"; using (OleDbConnection conn = new OleDbConnection(ConfigurationManager.ConnectionStrings["default"].ToString())) { OleDbCommand command = new OleDbCommand(sql, conn); command.Parameters.AddWithValue("Id", Id); conn.Open(); int count = Convert.ToInt32(command.ExecuteScalar()); if (count == 0) return false; else return true; } }
al igual que el ejemplo del link relacionado, se hace uso de ExecuteScalar, el cual devolverá simplemente la primer columna de la primer fila de la consulta.
LA funcionalidad que inserta tiene un pequeño detalles que hay que aclararlo ya que puede presentarse problemas en otras circunstancias.
Este se presenta al declarar el parámetro de fecha de nacimiento (líneas 28-30), se vera que se crea una variable del tipo OleDbParameter en donde se define el tipo de dato puntualmente.
Esto debe ser así ya que el método AddWithValue() no puede determinar para este tipo de dato cual es el correcto, cuando se le pasarle un objeto del tipo DataTime de .net, es por eso que hay que definirlo OleDbType.Date, y de esta forma funciona perfectamente.
private static ContactoEntity Insert(ContactoEntity contacto) { string sql = @"INSERT INTO Contacto (IdContacto ,Nombre ,Apellido ,FechaNacimiento ,Localidad ,Calle ,Numero) VALUES (@Id, @Nombre, @Apellido, @FechaNacimiento, @Localidad, @Calle, @Numero)"; using (OleDbConnection conn = new OleDbConnection(ConfigurationManager.ConnectionStrings["default"].ToString())) { int NextId = MaxId() + 1; OleDbCommand command = new OleDbCommand(sql, conn); command.Parameters.AddWithValue("Id", NextId); command.Parameters.AddWithValue("Nombre", contacto.Nombre); command.Parameters.AddWithValue("Apellido", contacto.Apellido); OleDbParameter param = new OleDbParameter("FechaNacimiento", OleDbType.Date); param.Value = contacto.FechaNacimiento; command.Parameters.Add(param); command.Parameters.AddWithValue("Localidad", string.IsNullOrEmpty(contacto.Localidad) ? (object)DBNull.Value : contacto.Localidad); command.Parameters.AddWithValue("Calle", string.IsNullOrEmpty(contacto.Calle) ? (object)DBNull.Value : contacto.Calle); command.Parameters.AddWithValue("Numero", contacto.Numero.HasValue ? contacto.Numero : (object)DBNull.Value ); conn.Open(); command.ExecuteNonQuery(); contacto.IdContacto = NextId; return contacto; } }
También se veras que la función MaxId() que permite recuperar el ultimo id ingresado no sufre cambio alguno con respecto a utilizado en una base de datos Sql Server
private static int MaxId() { string sql = @"SELECT MAX(IdContacto) FROM Contacto"; using (OleDbConnection conn = new OleDbConnection(ConfigurationManager.ConnectionStrings["default"].ToString())) { OleDbCommand command = new OleDbCommand(sql, conn); conn.Open(); return Convert.ToInt32(command.ExecuteScalar()); } }
2 – Actualización de la entidad (Update)
En la operación de actualización hay que remarcar dos puntos que son importantes y generan cambio con respecto a su equivalente en Sql Server
Uno al igual que como sucedió en la funcionalidad de Insert, es necesario definir el tipo de dato explicito para la fecha de nacimiento.
El segundo aspecto se refiere a que si bien hasta ahora pensábamos que los nombres de los parámetros guardaban una conexión, bajo la operación del actualización nos damos cuenta que no es tan así.
Es por ello que se notara que la creación de parámetros en este caso el “Id” ha sido declarado al final del resto, mientras que en si equivalente para Sql Server podría haber sido declarado en cualquier posición.
Esto marca un punto importante durante la actualización y es que el nombre sirve para tener una referencia a que parámetro estamos asignando el valor, pero para el provider de base de datos OleDb, lo que importa es la posición del parámetro en colección de Parameters.
Si en este código se declarar el parámetro “Id” en primer lugar la actualización no se realizaría adecuadamente.
private static ContactoEntity Update(ContactoEntity contacto) { string sql = @"UPDATE Contacto SET Nombre = @Nombre ,Apellido = @Apellido ,FechaNacimiento = @FechaNacimiento ,Localidad = @Localidad ,Calle = @Calle ,Numero = @Numero WHERE IdContacto = @Id"; using (OleDbConnection conn = new OleDbConnection(ConfigurationManager.ConnectionStrings["default"].ToString())) { OleDbCommand command = new OleDbCommand(sql, conn); command.Parameters.AddWithValue("Nombre", contacto.Nombre); command.Parameters.AddWithValue("Apellido", contacto.Apellido); OleDbParameter param = new OleDbParameter("FechaNacimiento", OleDbType.Date); param.Value = contacto.FechaNacimiento; command.Parameters.Add(param); command.Parameters.AddWithValue("Localidad", string.IsNullOrEmpty(contacto.Localidad) ? (object)DBNull.Value : contacto.Localidad); command.Parameters.AddWithValue("Calle", string.IsNullOrEmpty(contacto.Calle) ? (object)DBNull.Value : contacto.Calle); command.Parameters.AddWithValue("Numero", contacto.Numero.HasValue ? contacto.Numero : (object)DBNull.Value); command.Parameters.AddWithValue("Id", contacto.IdContacto); conn.Open(); int rows = command.ExecuteNonQuery(); return contacto; } }
3 – Eliminación de la entidad (Delete)
Esta operación no sufre cambio alguno con respecto a su equivalente en Sql Server, salvo los objetos de ado.net utilizados.
public static void Delete(int Id) { string sql = @"DELETE FROM Contacto WHERE [IdContacto] = @Id"; using (OleDbConnection conn = new OleDbConnection(ConfigurationManager.ConnectionStrings["default"].ToString())) { OleDbCommand command = new OleDbCommand(sql, conn); command.Parameters.AddWithValue("Id", Id); conn.Open(); command.ExecuteNonQuery(); } }
[C#]
|
[VB.NET]
|
Hola!, la verdad es que estos artículos están bastante bien expuesto, ójala todo en internet estuviera tan bien expuesto.
ResponderEliminarYa que estás tratando temas relativos a ADO.NET me gustaría plantearte unas dudas que tengo al respecto, por si me puedes echar una mano en alguna de ellas.
Las dudas son las siguientes:
1. La utilización de transacciones puede hacer que un tipo de bloqueo pesimista se convierta en uno optimista?
2. ¿Bajo que circunstancias no se debería emplear un Dataset con tipo?
3. ¿Puede ser reemplazado un Dataset sin tipo por uno con tipo?, ¿bajo que circunstancias? ..¿por ejemplo?
Forman parte de la preparación de un examen sobre tecnologías .NET. Se las preguntas, pero aún no tengo nada claras las respuestas.
La verdad creo que son preguntas bastante buscaditas, sobre todo la 1ª. Estaré encantado con cualquier ayuda al respecto.
Saludos y ciertamente un buen blog el tuyo!
Hola Leandro!, acabo de ver que tu mismo has respondido dos de las preguntas que te formulaba en mi mensaje anterior, en los foros de msdn.
ResponderEliminarMuchas gracias por tu ayuda!
Saludos!
-Alex_TS-
Hola necesito ayuda sobre como actualizar la cantidad en bodega cuando digito la cantidad recibida de determinados materiales en mi tabla recepcion_pedido
ResponderEliminarEspero me pueda ayudar!!!
Hola Karen
ResponderEliminarTe comento, no se si has analizado la seccion de actualizacion pero alli esta al clave, simplemente arma una consulta del tipo
UPDATE recepcion_pedido SET bodega = @cant WHERE Idbodega = @Idbodega
algo que no has detallado es como diferencias a una bodega de otra, imagino que tendras algun id, es por eso que lo agregue a la query en el WHERE, para que solo actualzice esa bodega en particular
lo unico que queda es agregar esta como veras en el articulo del post, parandole los parametros de @cant y @idbodega al objeto SqlCommand
espero te sea de utilidad este comentarios
saludos
Buena sugerencia pero necesito que la cantidad en bodega incremente cuando digito la cantidad_recibida
ResponderEliminares decir cantBodega= cantBodega+ Cantidad_recibida
Hola
ResponderEliminaren ese caso podrias hacer
UPDATE recepcion_pedido SET cantBodega = cantBodega + @cant WHERE Idbodega = @Idbodega
como veras tomas el campo con su valor actual y le sumas el del parametro.
saludos
Buenas Noches
ResponderEliminarSr. Leandro Tuttini
Descarque el zip VB.NET
hizo la extracion y abri el proyecto, pero cuando ya ejecutado, cuando guardo el registro, me da un mensaje de "El proveedor 'Microsoft.Jet.OLEDB.4.0' no está registrado en el equipo"
¿donde tengo que registrar el proveedor?
Saludos...
hola Roger
ResponderEliminartienes en la pc instalado office, concretamente Ms Access? sino esta instalsdo no va a funcionar
ademas estas usando una pc de 64 bits ? porque si es asi deberias cambiar el target del proyecto para que compile en 32, ya que Jet no soporta la arquitectura 64
saludos
me gustaria saber como puedo hacer una clase generica que haga las operaciones Create retrive update delete, que me sirva para cualquier aplicacion. que sea reutilizable.
ResponderEliminarhola marcelo
ResponderEliminarcreo que no entendi la pregunta
podrias programar en capas, por lo que crearias uan capa de datos con als operaciones de insert, actualizacion, etc para operar con las entidades de la db
[N-Tier] – Desarrollo en capas - Ejemplo Facturacion - parte 3
de esta forma creas las operaciones que cometas y puedes reutilizarlas en varias aplicaciones
saludos
hola leandro saludos
ResponderEliminarcomo puedo incorporar la base de datos al proyecto de vb me refiero tengo que crear un .exe para cualquier pc y el programa tiene conecion a la base de datos como se realiza ese procedimiento
gracias de antemano por sus aportes
hola Manuel
ResponderEliminarpor base de datos te refieres a usar Ms Access ?
el articulo utiliza esta base de datos
si es Acces con que solo este el archivo de la db junto al .exe, o en el connection string le indiques la ruta correcta alcanzaria
despues la db es solo un archivo
saludos
no leandro perdon por no explicar
ResponderEliminarme refiero a sql
gracias nuevamente
hola Manuel
ResponderEliminarpor sql te refieres a sql server ? porque sql es la notacion para realizar consultass a las base de datos, Ms Access usa sql, MySql usa sql, sql server usa sql, todas las dbs usan sql
imagino se trata de sql server, en ese caso usas la db con attach automatico o sea tienes el .mdf dentro de la estructura de la solucion? si es asi aplica igual que con Ms Access solo incluyes este en la distribucion, pero ojo en la pc del usuario tambien deberias instalar el sql server express para que inicie el servicio
saludos
Disculpa Leandro si deseó trabajar en Sql server utilizando la versión gratuita la express 2008 esta me serviría para poder tener una aplicación clientes servidor. usando esta versión express para una base de datos algo más robusta que Access. Y estos códigos que. Estas colocando serviría de maravilla para Sql server..? Disculpa sí esté no era el foro para preguntarte esto pero de alguna manera necesitaba contactarte. Saludos de Venezuela
ResponderEliminarhola Enyelber
ResponderEliminarusas sql server es una buena idea para contar con una db robusta
pero no entendi la pregunta que planteas, o cual seria la duda
saludos
Hola! Muchas gracias por toda la info!
ResponderEliminarAhora hay algo que estoy tratando de hacer y no encuentro la forma. Estoy trabajando con visual studio 2005 y una BD Access.
Quiero hacer un INSERT masivo a una de as tablas, con datos que guarde dentro de un Dictionary<>.
Podrías ayudarme ya que no encontré otra forma más que poner el insert dentro del foreach que recorre el Dictionary.
Muchas gracias!!
Como estas Leandro;
ResponderEliminarEstoy haciendo una aplicación sencilla donde uso tu codigo Login – Usando Password con Hash. En access me corre de maravilla pero quise hacerlo con una BD SQL Server y hago lo siguiente:
1.- Cree un formulario de Inicio de Sesión y en su codigo tiene lo siguiente:
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Linq
Imports System.Text
Imports System.Windows.Forms
Public Class LoginForm1
Private Sub OK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK.Click
Dim nombre As String = UsernameTextBox.Text
Dim password As String = PasswordTextBox.Text
If LoginService.Autenticar(nombre, password) Then
Me.DialogResult = DialogResult.OK
Else
Me.DialogResult = DialogResult.Abort
End If
End Sub
Private Sub Cancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Cancel.Click
Me.Close()
End Sub
End Class
En la Clase Login.VB tengo lo siguiente:
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Data.SqlClient
Imports System.Configuration
Public NotInheritable Class LoginService
Public Shared Function Autenticar(ByVal usuario As String, ByVal password As String) As Boolean
Dim sql As String = "SELECT COUNT(*) " & _
"FROM Usuarios " & _
"WHERE NombreLogin = @nombre AND Password = @password"
Using conn As New SqlConnection(ConfigurationManager.ConnectionStrings("default").ToString())
conn.Open()
Dim command As New SqlCommand(sql, conn)
command.Parameters.AddWithValue("@nombre", usuario)
Dim hash As String = Helper.EncodePassword(String.Concat(usuario, password))
command.Parameters.AddWithValue("@password", hash)
Dim count As Integer = Convert.ToInt32(command.ExecuteScalar())
If count = 0 Then
Return False
Else
Return True
End If
End Using
End Function
End Class
inmediatamente me da un error en ConfigurationManager me indica Error 1 'ConfigurationManager' no está declarado. Puede que esté inaccesible debido a su nivel de protección.
yo copie la Base de Datos que tenias en el ejemplo de Hast y agregue esa al proyecto, indicandole conectar una Base de datos y le indique que era un Archivo de base de datos de Microsoft SQL Server (SqlClient) y le indique la ruta donde esta la BD. pero no se porque me da el error del ConfigurationManager. estoy trabajando con vs2012 y sqlserver que viene integrado en visual... gracias por la ayuda de antemano
hola Jéssica
ResponderEliminarpero ese diccionario solo tiene dos valores
podrias recorrerlo usando
foreach(KeyValuePair item in diccionario){
}
asi podrias armar el insert
http://social.msdn.microsoft.com/Forums/es/vcses/thread/3998fceb-9b98-4f05-8588-d59373781d2b
como en la pregunta del link analiza como se arma el command para ir pasando los parametros y el cmd.Parameters.Clear(); en cada loop
saludos
hola Enyelber
ResponderEliminarrecuerda que debes agregar al referencia a System.Configuration
ademas de definir el
using System.Configuration
para que el ConfigurationManager se pueda usar
saludos
Listo era eso... Gracias Leandro
ResponderEliminarLeandro ahora tengo este problema
ResponderEliminaren este codigo de la clase
Public NotInheritable Class LoginService
Public Shared Function Autenticar(ByVal usuario As String, ByVal password As String) As Boolean
Dim sql As String = "SELECT COUNT(*) " & _
"FROM Usuarios " & _
"WHERE NombreLogin = @nombre AND Password = @password"
Using conn As New SqlConnection(ConfigurationManager.ConnectionStrings("default").ToString())
conn.Open()
Dim command As New SqlCommand(sql, conn)
command.Parameters.AddWithValue("@nombre", usuario)
Dim hash As String = Helper.EncodePassword(String.Concat(usuario, password))
command.Parameters.AddWithValue("@password", hash)
Dim count As Integer = Convert.ToInt32(command.ExecuteScalar())
If count = 0 Then
Return False
Else
Return True
End If
End Using
End Function
la sentencia, Using conn As New SqlConnection(ConfigurationManager.ConnectionStrings("default").ToString()) me indica que No se controló System.NullReferenceException... lo estraño que en el ejemplo que tu tienes de Hash funcionaba pero ahora me sale el mismo error
hola Enyelber
ResponderEliminarhas validado que en el app.config este presente el tag que define la configuracion del connection string
porque puede dar ese error cuando no encuantra el "default" el el archivo de configuracion
saludos
hola leandro,
ResponderEliminarmodifique mi App.config
pero ahora me indica el siguiente detalle:
No se puede abrir la base de datos en la versión 706. Este servidor es compatible con la versión 662 y anteriores. No se admite esta ruta de actualización.
voy a revisar que pasa. pero ya me estoy acercando jejeje
hola Enyelber
ResponderEliminarese error se suele generar cuando tienes una db que fue creada con un sql server 2008 R2 en una instalacion que no es R2
valida que sql server tienes en la pc, si es la que instala visual studio, entonces quizas deberias quitar ese sql server y descargar la version sql server 2008 R2 express
saludos
efectivamente tengo la versión 2012. ya pude conectar la BD con esta configuración.
ResponderEliminarestubo bueno el dolor de cabeza pero se aprende. saludos y gracias
Buenas...
ResponderEliminarEstoy muy interesado en este codigo...
Estoy desarrollando una aplicacion en Visual Studio 2013 con base de datos Acces 2013...
Necesito lo siguiente:
El programa va a ser usado por varias personas en distintas computadoras de manera independiente, al no tener acceso a internet estas computadoras no puedo usar una base de datos en la nube para que todas se conecten a ella, asi que cada laptop tendra su propia base de datos.
En la Oficina principal tendran tambien el programa, pero alli necesitaran todos los datos de las bases de datos de todos los usuarios por cuestiones de reportes generales.
Como una base de datos acces a la larga pesa mucho para ser enviada por email, se me ocurrio la idea de generar un archivo excel que contiene los datos de las bases de datos.
Cree un form en donde cargo ese Excel en un DataGridView, hasta los momentos me ha salido todo bien... el archivo carga perfecto y me muestra todos los valores del excel en el DataGridView.
Lo que necesito ayuda es para tomar todos esos datos mostrados en el DataGridView y Actualizar la base de datos asosiada a la aplicacion.
Necesito que los datos existentes se actualicen y los que no estan se generen... esto para evitar duplicados...
La tabla uno la filtro por numero de Cedula, en la base de datos tengo como valor unico, que no pueda repetirse.
La tabla dos los campos que no pueden repetirse simultaneamente son Cedula y Fecha de consulta medica.
Como podria hacer eso? como podria actualizar mi base de datos tomando en cuenta lo que comento?
Agradeceria muuuuuchisimo su ayuda ya que llevo 3 dias dando vueltas en la cabeza e investigando en internet y no he dado con una solucion.
Saludos...