Sei sulla pagina 1di 79

ADO.

NET

ueves, 8 de noviembre de 2012
[ADO.NET] Ms Access y arquitectura 64bit

Cuando desarrollamos bajo una plataforma con arquitectura de 64 bits se pueden
presentar problema si la db usada se trata de Ms Access
Este problema se presenta porque el motor que usa para establecer la conexin desde
cdigo no provee compatibilidad con esta arquitectura
Para efectuar el artculo se hizo uso una PC con arquitectura 64bits

Base de datos .mdb

Para demostrar el problema se confecciono un ejemplo simple

Una base de datos Access 2000 integrada en proyecto la cual lista contactos en un grid
01.string connstring = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=Contactos.mdb;User Id=admin;Password=;";
02.
03.try
04.{
05.using (OleDbConnection conn = new OleDbConnection(connstring))
06.{
07.conn.Open();
08.
09.string query = "SELECT * FROM Contactos";
10.OleDbCommand cmd = new OleDbCommand(query, conn);
11.OleDbDataAdapter da = new OleDbDataAdapter(cmd);
12.DataTable dt = new DataTable();
13.da.Fill(dt);
14.
15.dataGridView1.DataSource = dt;
16.}
17.}
18.catch (Exception ex)
19.{
20.MessageBox.Show(ex.Message);
21.}
El proveedor utilizado
Provider=Microsoft.Jet.OLEDB.4.0
Si se ejecuta sin realizar ningn otro cambio se obtendr
The 'Microsoft.Jet.OLEDB.4.0' provider is not registered on the local machine.

Para que esto no suceda la solucin es cambiar el Platform Target del proyecto, para
esto solo se debe ir a la propiedades del proyecto

Y all cambiar la opcin mencionada a x86, con esto haremos que el .exe compile con
compatibilidad a 32bits

Ahora si al ejecutar la aplicacin funcionara sin problemas


Base de datos .accdb

Otra alternativa que podra evaluarse es la utilizacin de ACE.OLEDB como proveedor
para trabajar con la db Ms Access, para ello seguramente se necesite instalar
Componente redistribuible del motor de base de datos de Microsoft Access 2010
Nota: si se tiene el Office 2010 (o superior) en la pc quizs no se requiera la
instalacin
Al cambiar de proveedor, ya no se usara Jet por lo que se define
Provider=Microsoft.ACE.OLEDB.12.0

Al ejecutar la aplicacin funciona correctamente ms all de estar definida para
compilar a 64bits
Nota: tambin se prob ACE.OLEDB con una base de datos .mdb (generada con Ms
Access 2010 pero grabada con compatibilidad con Access 2000) pudiendo establecer la
conexin correctamente sin que afectara la arquitectura 64bits

Conclusin

Si se quiere hacer uso de Jet como proveedor para establecer la conexin a los datos
ser necesario cambiar en el proyecto la plataforma a la cual se compila
Para evitar el problema se har uso del proveedor ACE.OLEDB el cual proporciona
compatibilidad con 64bit
Publicado por Leandro Tuttini en 5:20 15 comentarios:
Etiquetas: ADO.NET
martes, 8 de marzo de 2011
[Anlisis] CampusMVP - ADO.NET Entity Framework 4.0 -
Aplicaciones y servicios centrados en datos

Diariamente durante la participacin en los foros noto que tema recurrente esta
relacionado con el accesos a datos, existen muchas dudas de las tcnicas que se deben
aplicar para trabajar la informacin de un repositorio.
En el blog trato de ejemplificar de forma practica las situaciones mas comunes que he
visto planteadas en el foro, pero debo reconocer que son muchas y muy variadas como
para tratarlas todas.
Mas que nada estas se generan por un nivel inicial de quin consulta, sumado a la no
dedicacin del tiempo suficiente para madurar la tecnologa, quizs realizando
practicas que vayan subiendo en complejidad de de forma progresiva muchas de las
dudas nunca se hubieran planteado. Por lo general si se busca como gua un libro
sobre el tema, esta podra ser una alternativa, pero seguramente est en ingles, y
muchas veces el no tener un gran dominio del idioma puede terminar restando,
haciendo muy lento el aprendizaje.
Lo anteriormente dicho genera un problema : "falta de capacitacin". La profesin de
sistemas requiere de constante capacitacin que permita obtener nuevas habilidades
sobre un tema; sino se madura la tecnologa es ms que seguro que se encontrarn
miles de trabas.
Es aqu donde CampusMVP puede aportar un gran beneficio, tuve la oportunidad
gracias al contacto de Fred Lores de analizar unos de los cursos online que brindan
y la verdad me qued maravillado, me refiero a este en particular:
Preparacin de la certificacin 70-516 TS: Accessing Data with Microsoft .NET
Framework 4
Como coment ms arriba el acceso a datos y manipulacin de la informacin desde
mi punto de vista es un aspecto importantsimo en el desarrollo de sistemas, ojo con
esto no estoy minimizando que la presentacin (WinForms, WFP, asp.net) y
comunicacin (WCF) sean aspectos menos importantes, pero s noto que el trabajar
con datos es uno de los aspecto que ms dudas y consultas generan todos los das.
Esta inquietud se la plate a Fred y es por eso que de todos los cursos expuestos en
CampusMVP el de acceso a datos fue el que destaco.
Despus de recorrerlo un buen rato destaco las caractersticas:
el curso est totalmente en espaol, lo cual no hay que menospreciar teniendo
en cuenta que en sistemas no abunda documentacin en nuestro idioma, el
material comnmente encontrado esta en ingls, lo cual implica ir algo ms
lento si es un idioma que no se domina del todo.
claramente explicado y con una lectura muy simple, algo que me llam la
atencin es lo natural que se da la lectura de los temas, por supuesto esto
tambin est relacionado a la experiencia previa que uno tenga. Si ya se han
realizado algunas incursiones es lgico que resulte ms simple la lectura, pero
as y todo resultan muy claros los temas tratados.
la complejidad de cada tema avanza de forma progresiva, a medida recorren los
temas estos van aumentando de complejidad, el curso est estructurados de
forma escalonada para que resulte prctico.
Este punto, unido a los ejemplo de cdigo que se brindan durante la
explicacin, aporta una clara comprensin de cada tema tratado.
tiene la cantidad justa de imgenes que explican paso a paso como realizar
cada tarea, pareciera un dato menor pero es importante que las explicaciones
escritas se complementen con imgenes y que sto se haga de forma adecuada
no es simple (como se dice: una imagen vale ms de mil palabras, pero
tampoco es cuestin de desbordar todos los temas con miles de print screen de
pantallas).
Adems se cuenta con videos que complementan aquellos temas en donde se
requiere mostrar un proceso completo.
En el link del curso se puede observar el temario tratado, pero este no solo incluye
ADO.NET para el acceso a datos, sino que cubre en totalidad la certificacin 70-
516 (para aquel que quiera rendirla, lo cual es recomendable si se realiza el curso)
Es por eso que se incluyen puntos relacionado con ORM, ms que til si se quiere
aprender las ltimas novedades que agilicen el desarrollo:
Entity Framework
Linq to Sql
Es ms, este va mas all incluyendo tecnologas actuales como ser:
Sync Framework
WCF Data Service
Al acceder al curso se dispone de autoevaluaciones para afianzar lo aprendido durante
la unidad.
Para coronar el postre con una frutilla, el acceso al curso permite la descarga de 3
libros en formato pdf, entre ellos el ms destacado.
ADO.NET Entity Framework 4.0 - Aplicaciones y servicios centrados en datos
Conclusin, si se busca aprender o profundizar los conocimiento en el acceso a datos,
en espaol, de simple lectura y comprensin, sumado a una buena estructura en el
temario, este curso es el indicado.
Publicado por Leandro Tuttini en 16:37 4 comentarios:
Etiquetas: ADO.NET
domingo, 19 de septiembre de 2010
[ADO.NET] Filtrar rango de fechas

Introduccin
Uno de los principales problemas que se pueden encontrar cuando se confecciona una
consulta es el trabajo con campos del tipo fecha.
Por lo general estos campos no solo persisten la fecha, sino que tambin registran la
hora.
Es por eso que ciertas consultas pueden no retornar los valores deseados, aunque se
este definiendo correctamente los parmetros de la consulta.
Planteo del problema
Para demostrar el problema se plantea el log de actividades del usuario, en donde se
registras las acciones que este tiene en la aplicacin. Pero el problema se presenta
cuando se necesita consultar estos registros para analizar las acciones realizadas en un
determinado rango de das, por supuesto se quiere ver los das completo, y es aqu
donde nos encontramos con el inconveniente.
Si se analiza los registros de la tabla se ve que el registro de la fecha no solo usa el
da, sino tambin la hora.

La aplicacin de ejemplo cuenta con dos opciones de bsqueda, pero en este primer
anlisis nos centraremos en el primer botn de nombre Buscar (sin usar CONVERT),
al utilizarlo veremos el resultado de la imagen:

Pero con solo comparar los registros obtenido con los que se encuentran en la tabla,
nos damos cuenta que hay un problema, esta retornando menos filas de las esperadas,
la pregunta seria, porque sucedi esto ?
El cdigo utilizado para obtener los registro es el siguiente :
01.public static LogActividades.RegistroActividadesDataTable
GetFilterByDateRange(DateTime desde, DateTime hasta)
02.{
03.LogActividades.RegistroActividadesDataTable dt
= newLogActividades.RegistroActividadesDataTable();
04.
05.using (SqlConnection conn
= newSqlConnection(ConfigurationManager.ConnectionStrings["default"].ToSt
ring()))
06.{
07.conn.Open();
08.
09.string sql = @"SELECT Id, Descripcion, fecharegistro, usuario
10.FROM RegistroActividades
11.WHERE fecharegistro >= @desde AND fecharegistro <= @hasta";
12.
13.SqlCommand cmd = new SqlCommand(sql, conn);
14.cmd.Parameters.AddWithValue("@desde", desde);
15.cmd.Parameters.AddWithValue("@hasta", hasta);
16.
17.SqlDataAdapter da = new SqlDataAdapter(cmd);
18.da.Fill(dt);
19.
20.}
21.
22.return dt;
23.}
El parmetro de la fechas toma el valor directo de los controles que estan en la
pantalla, pero esta fecha aunque no se conozca tambin lleva consigo un componente
de hora, que puede ser apreciado si se detiene el cdigo y se analiza el valor:

El tipo de dato DataTime, lleva una hora aunque esta no se especifique concretamente.
Esto aclara bastante el porque la consulta arroja menos tems de los esperados, resulta
que esta quitando aquellos registros en donde la hora sea menos a las 12 AM
Solucin del problema
La solucin al problema se obtiene usando una funciona en la query, que aplicada
sobre los campos de fecha en el filtro quiten la componente de la hora. En realidad no
remueve la hora, sino que la normaliza para que esta tambin tenga las 12 AM, por lo
tanto el filtro no descartara ningn registro.
Para esto se har uso de la funcin CONVERT, la cual permite convertir entre tipos de
datos.
CAST y CONVERT (Transact-SQL)
Si se ejecuta una consulta usando esta funcin se podra apreciar lo comentado mas
arriba:

Las fechas de los registros dejan de tener la hora original, ahora todos presentan las
12 AM, esto es justamente lo que ayudara en el filtro.
Entonces si ahora se aplica lo comentado al cdigo se obtiene el resultado esperado
(usar el botn Buscar (usando CONVERT)):

Para que esto resulte se utilizo el siguiente cdigo:
01.public static LogActividades.RegistroActividadesDataTable
GetFilterByDateRangeRemoveHour(DateTime desde, DateTime hasta)
02.{
03.LogActividades.RegistroActividadesDataTable dt
= newLogActividades.RegistroActividadesDataTable();
04.
05.using (SqlConnection conn
= newSqlConnection(ConfigurationManager.ConnectionStrings["default"].ToSt
ring()))
06.{
07.conn.Open();
08.
09.string sql = @"SELECT Id, Descripcion, fecharegistro, usuario
10.FROM RegistroActividades
11.WHERE CONVERT(smalldatetime, CONVERT(char(10), fecharegistro, 103),
103) >= @desde
12.AND CONVERT(smalldatetime, CONVERT(char(10), fecharegistro, 103), 103)
<= @hasta";
13.
14.SqlCommand cmd = new SqlCommand(sql, conn);
15.cmd.Parameters.AddWithValue("@desde", desde);
16.cmd.Parameters.AddWithValue("@hasta", hasta);
17.
18.SqlDataAdapter da = new SqlDataAdapter(cmd);
19.da.Fill(dt);
20.}
21.
22.return dt;
23.}
El uso del CONVERT aplicado en los campo de fecharegistro, es quien quita la
componente de la hora y permite aplicar el filtro correctamente.

Alternativa usando Between
Como alternativa al mtodo anterior se podra lograr usando el Between en la query
para filtrar por el rango de fechas.
En el Form2 del ejemplo se podr encontrar la implementacin de este caso.
01.public static LogActividades.RegistroActividadesDataTable
GetFilterByDateRangeWithBetween(DateTime desde, DateTime hasta)
02.{
03.LogActividades.RegistroActividadesDataTable dt
= newLogActividades.RegistroActividadesDataTable();
04.
05.using (SqlConnection conn
= newSqlConnection(ConfigurationManager.ConnectionStrings["default"].ToSt
ring()))
06.{
07.
08.string sql = @"SELECT Id, Descripcion, fecharegistro, usuario
09.FROM RegistroActividades
10.WHERE CAST(CONVERT(CHAR(8), fecharegistro, 112) AS INT) BETWEEN
CAST(CONVERT(CHAR(8), @desde, 112) AS INT)
11.AND CAST(CONVERT(CHAR(8), @hasta, 112) AS INT)";
12.
13.SqlCommand cmd = new SqlCommand(sql, conn);
14.cmd.Parameters.AddWithValue("@desde", desde);
15.cmd.Parameters.AddWithValue("@hasta", hasta);
16.
17.SqlDataAdapter da = new SqlDataAdapter(cmd);
18.da.Fill(dt);
19.}
20.
21.return dt;
22.}
La lgica principal se encontrara en el mtodo creado para realizar la consulta, all se
ha utilizado el BETWEEN para definir el filtro entre un rango, pero este tienen un
problema requiere de un formato especial que justamente el CONVERT (con el cdigo
112) nos proporciona.
Esta conversin lleva la fecha al formato yyyyMMdd, o sea si tenemos la fecha
10/06/2010, ser formateada a 20100610, claramente un numero, pero primero
deber pasar por un CHAR para adecuar la conversin del formato de la fecha y luego
si ser convertido a un valor numrico.

Ejemplo de Cdigo
El cdigo publicado fue desarrollado con visual Studio 2008.
La base de datos utilizada es el Sql Server Express 2008.
En el proyecto encontraran una carpeta de nombre Script que contiene el archivo .sql
que podrn usar en el Sql Server Management Studio para crear la estructura de la
base de datos en caso de tener problemas con el archivo .mdf
En caso de usar la base de datos integrada al servicio de Sql Server, se deber
cambiar la cadena de conexin definida en el App.config

[C#]

[VB.NET]

Publicado por Leandro Tuttini en 19:47 73 comentarios:
Etiquetas: ADO.NET
martes, 4 de mayo de 2010
[Linq] DataSet Agrupar y totalizar

Introduccin

En este articulo analizaremos como trabajar con los datos procedentes de un
datatable, realizando operaciones por medio de la ayuda de linq, y luego confeccionado
un datatable distinto, cuya estructura de campos difiere de la original.
Para esta operacin se contara con un datatable con documento de clientes, y un
campo total que informa cuantos de estos se tienen registrados.
La idea es obtener en otro datatable la cantidad total agrupando todos los clientes.

Agrupar con Linq

Para esta operacin se realizara una agrupacin mediante la funcionalidad que provee
linq.
01.private void button1_Click(object sender, EventArgs e)
02.{
03.IEnumerable<IGrouping<string, DataRow>> query = from
item inDatos().AsEnumerable()
04.group item by item["Documento"].ToString() into g
05.select g;
06.
07.
08.DataTable resultado = Transformar(query);
09.
10.dataGridView1.AutoGenerateColumns = true;
11.dataGridView1.DataSource = resultado;
12.
13.}
Como se observa en la query de linq se agrupa por medio del campo Documento, y
el resultado de esta operacin se alojo en g, valor que es devuelto en la consulta.
Si bien podra haberse igualado toda la consulta a una variable definida como var,
esto hubiera imposibilitado el pasaje de la informacin a un mtodo de transformacin,
para la creacin del nuevo datatable, es por eso que se crea el IEnumerable<>, que
contiene el IGrouping<> tambin genrico.

Creacin del nuevo DataTable

En esta operacin en una primera implementacin es algo manual, ya que toma el
resultado de la consulta linq e itera para cargar el nuevo datatable, y en su camino
realiza las operaciones de calculo.
01.private DataTable Transformar(IEnumerable<IGrouping<string, DataRow>>
datos)
02.{
03.//
04.// Se define la estructura del DataTable
05.//
06.DataTable dt = new DataTable();
07.dt.Columns.Add("Documento");
08.dt.Columns.Add("CantRegistros");
09.dt.Columns.Add("Total");
10.
11.//
12.// Se recorre cada valor agruparo por linq y se vuelca el resultado
13.// en un nuevo registro del datatable
14.//
15.foreach (IGrouping<string, DataRow> item in datos)
16.{
17.DataRow row2 = dt.NewRow();
18.row2["Documento"] = item.Key;
19.row2["CantRegistros"] = item.Count();
20.row2["Total"] = item.Sum<DataRow>(x => Convert.ToInt32(x["Total"]));
21.
22.dt.Rows.Add(row2);
23.}
24.
25.return dt;
26.}
Debe observarse como se trabaja con los mtodos extendidos, y en ellos se aplica la
funcionalidad Lambda, puntualmente al indica que campo debe sumarse.

[C#]



Creacin del DataTable con CopyToDataTable()

Una alternativa algo mejor a la transformacin de datos podras ser por medio del uso
del mtodo de extensin CopyToDataTable()
DataTableExtensions.CopyToDataTable<(Of <(T>)>)
Hay que remarcar un punto con este mtodo, ya que de forma estndar solo permite
convertir a DataTable aquellas consulta linq que devuelvan como resultado una
DataRow.
Pero en nuestro ejemplo planteado esto es diferente ya que el datatable a devolver
requiere de una transformacin de los registro con respecto a los datos originales.
Pero esta situacin esta contemplada, ya que es posible implementar un mtodo
CopyToDataTable<> genrico, en donde a base de un tipo de dato se arme un
datatable.
Para esta implementacin, se har uso de la explicacin proporcionada por siguiente
articulo:
Cmo implementar CopyToDataTable<T> donde el tipo genrico T no es un objeto
DataRow
El cdigo del link de msdn, se ha volcado al archivo de nombre CopytoDataTable.cs,
se podr observar en el cdigo de ejemplo adjunto en el articulo.
La implementacin de la funcionalidad quedo reducida al siguiente cdigo:
01.private void button1_Click(object sender, EventArgs e)
02.{
03.
04.var query = from item in Datos().AsEnumerable()
05.group item by item["Documento"].ToString() into g
06.select new DocumentoResult
07.{
08.Documento = g.Key,
09.CantRegistros = g.Count(),
10.Total = g.Sum(x => Convert.ToInt32(x["Total"]))
11.};
12.
13.
14.DataTable resultado = query.CopyToDataTable<DocumentoResult>();
15.
16.dataGridView1.AutoGenerateColumns = true;
17.dataGridView1.DataSource = resultado;
18.
19.}
Esta nueva alternativa ya no necesita iterar por cada registro que dio como resultado
la consulta linq, es mas se puede hacer uso del var, puesto que no es necesario
pasar por parmetro la consulta para trabajarla.
Pero si se necesito de un pequeo cambio, en donde se ha definido una clase, de
nombre DocumentoResult, la cual define los campos del nuevo DataTable.
1.public class DocumentoResult
2.{
3.public string Documento { get; set; }
4.public int CantRegistros { get; set; }
5.public int Total { get; set; }
6.
7.}
Siendo esta la clase usada en la definicin del mtodo genrico CopyToDataTable<>,
cuando se usa en la lnea:
DataTable resultado = query.CopyToDataTable<DocumentoResult>();

[C#]


Publicado por Leandro Tuttini en 14:49 16 comentarios:
Etiquetas: ADO.NET, C#, Linq
domingo, 7 de febrero de 2010
C# DataTable Pasar Filas a Columnas y agregar filas
adicionales

Introduccin
Basado en una pregunta que he visto en uno de los foros arme unos ejemplo que
explica como poder trabajar con DataTables.
Bsicamente el planteo de las consultas se hacan porque era necesario realizar tareas
que requieren de la iteracin de datos existentes, para ser volcados en un nuevo
conjunto de datos resultante.
se atacara dos aspectos en este articulo
como agregar una lnea en blanco, segn cierto corte de control
como unir dos conjuntos de datos, pero que estas sean representadas en
columnas

Lnea en Blanco
Como se pareca en el cdigo es necesario ciclar cada tem de los datos obtenidos y
mediante un procesamiento o corte de control en cuyo ejemplo es representado
mediante un asiento contable, el cual solo es a modo de ejemplo.

01.private void Form2_Load(object sender, EventArgs e)
02.{
03.//se obtiene el conjunto de datos
04.DataTable dtAsientos = GetDatos();
05.
06.//se crea el dataset resultado
07.DataTable dt = new DataTable();
08.
09.dt.Columns.Add("Asiento");
10.dt.Columns.Add("Importe");
11.
12.// variables que actuaran como flag para el corte de control
13.// en el ciclo
14.string asientActual = "";
15.double importe = 0;
16.
17.
18.foreach (DataRow row in dtAsientos.Rows)
19.{
20.
21.if (string.IsNullOrEmpty(asientActual))
22.{
23.// la primera vez que entre esta sin inicializar la variable
"asientActual"
24.// por eso entrara por este pregunta del if
25.
26.asientActual = Convert.ToString(row["asiento"]);
27.importe = Convert.ToDouble(row["Importe"]);
28.}
29.else if (Convert.ToString(row["asiento"]) == asientActual)
30.{
31.//si el asiento es el mismo solo acumulo el importe
32.importe += Convert.ToDouble(row["Importe"]);
33.}
34.else
35.{
36.
37.//aqui es donde se agregas la nueva fila
38.DataRow blankRow = dt.NewRow();
39.
40.blankRow["Asiento"] = "";
41.blankRow["Importe"] = importe.ToString("N2");
42.dt.Rows.Add(blankRow);
43.
44.//se inicializa las variable al nuevo asiento
45.asientActual = Convert.ToString(row["asiento"]);
46.importe = Convert.ToDouble(row["Importe"]);
47.}
48.
49.DataRow newRow = dt.NewRow();
50.
51.newRow["Asiento"] = row["Asiento"];
52.newRow["Importe"] = row["Importe"];
53.
54.dt.Rows.Add(newRow);
55.
56.}
57.
58.// se agrega el registro que refleja el acumulado
59.// para el ultimo asiento, esto se hace fuera del foreach
60.// ya que no se poden registro adicionales que agreguen el ultimo
valor
61.DataRow lastRow = dt.NewRow();
62.
63.lastRow["Asiento"] = "";
64.lastRow["Importe"] = importe.ToString("N2");
65.dt.Rows.Add(lastRow);
66.
67.//se carga el nuevo dataset en la grilla
68.dataGridView1.AutoGenerateColumns = true;
69.dataGridView1.DataSource = dt;
70.
71.}
En el cdigo adems se lleva un acumulado de los importes de cada registro, y justo
en el momento de insertar la lnea adicional es que se usa este importe para informar
el total del asiento.

Pasar Filas a Columnas, con dos Datatable
en este ejemplo se observaran dos orgenes de datos, lo cuales sern procesador para
obtener un nico resultado final, pero en donde la unin no sea a nivel de registros,
sino que se agregaran las columnas de uno a continuacin de las otras.

01.private void Form1_Load(object sender, EventArgs e)
02.{
03.//
04.// obtengo los datos que seran unidos postermente
05.//
06.DataTable dt1 = GetDatos();
07.DataTable dt2 = GetDatos2();
08.
09.//
10.// se crea un nuevo datatable resultande de la union
11.//
12.DataTable dt = new DataTable();
13.
14.dt.Columns.Add("Columna1");
15.dt.Columns.Add("Columna2");
16.dt.Columns.Add("Columna3");
17.dt.Columns.Add("Columna4");
18.dt.Columns.Add("Columna5");
19.
20.
21.//
22.// se recorre el primer origen de datos
23.// en este se insertan los registros
24.//
25.foreach (DataRow row in dt1.Rows)
26.{
27.DataRow newRow = dt.NewRow();
28.
29.newRow["Columna1"] = row["Columna1"];
30.newRow["Columna2"] = row["Columna2"];
31.
32.dt.Rows.Add(newRow);
33.
34.}
35.
36.//se recorre el segundo origen de datos
37.for (int i = 0; i < dt2.Rows.Count; i++)
38.{
39.DataRow copyRow = null;
40.
41.// se pregunta si el indice del registro existe
42.// o debe crearse uno adicional, ya que el segundo origen de datos
43.// posee mas registro que el primero
44.if (dt.Rows.Count <= i)
45.{
46.copyRow = dt.NewRow();
47.dt.Rows.Add(copyRow);
48.}
49.else
50.copyRow = dt.Rows[i];
51.
52.DataRow originalRow = dt2.Rows[i];
53.
54.copyRow["Columna3"] = originalRow["Columna3"];
55.copyRow["Columna4"] = originalRow["Columna4"];
56.copyRow["Columna5"] = originalRow["Columna5"];
57.}
58.
59.
60.dataGridView1.AutoGenerateColumns = true;
61.dataGridView1.DataSource = dt;
62.
63.}

En el cdigo se observar que el dataset de resultado al crearlo se le definen las
columnas de los dos dataset que son usados de origen de datos.
El primer ciclo por contar con el dataset resultado sin valores simplemente vuelva los
registros all.
El segundo es algo mas complejo ya que debe usas los ndices de los registros creados
en el paso anterior.
Adems debe verificar si es que este segundo grupo de registro es mayor que el
anterior de agregar las filas adicionales.
Conclusin
Para trabajar con DataTables para manipular la informacin que estos contienen y
poder forma un conjunto de datos adicional que represente correctamente la datos en
la disposicin que se necesita, es necesario mencionar que un punto a tener en cuenta
y esta referido al orden en se que proveen los datos iniciales.
Como se vern en ambos ejemplo el orden es importante ya que este determina el
xito del corte que se aplica al recorrer y procesar cada registro.
[C#]


Publicado por Leandro Tuttini en 19:32 7 comentarios:
Etiquetas: ADO.NET, C#, WinForm
jueves, 21 de enero de 2010
C# - [ADO.NET] Parte 6 - Campos Auto numricos (Identity)

Introduccin

Se basara la explicacin de este articulo de uno anterior en donde se aprendi de una
forma simple y por medio de un ejemplo completo a trabajar los datos con ado.net
[ADO.NET] Parte 5 - Ejemplos Simples Operaciones CRUD
Por lo cual tomando ese ejemplo de base se pasara a explicar como trabajar con
campos del tipo Autonumricos o Identity.
Como es sabido en estos tipos de campos es la base de datos la que genera el Id del
registro que se inserta, por lo tanto las modificaciones solo afectaran a las operaciones
INSERT de la aplicacin de ejemplo.
En la base de datos se ha realizado el siguiente cambio en la tabla:


1- Obtener Identity en la misma consulta

En este ejemplo se har uso de una consulta combinada en donde en la misma
ejecucin se insertara el registro y a la vez se recuperara el identificador autonumrico
generado.
[C#]
01.private void btnGuardar_Click(object sender, EventArgs e)
02.{
03.//
04.// Validaciones
05.//
06.int Id = 0;
07.if (!string.IsNullOrEmpty(txtId.Text))
08.{
09.if (!int.TryParse(txtId.Text, out Id))
10.{
11.MessageBox.Show("El Id debe ser un valor numerico");
12.return;
13.}
14.}
15.
16.if (Exists(Id))
17.{
18.bool result = Update(Id, txtNombre.Text, txtDireccion.Text,
dtpFechaNanimiento.Value);
19.
20.if (result)
21.MessageBox.Show("El registro se ha actualizado correctamente.");
22.}
23.else
24.{
25.int id = Insert(txtNombre.Text, txtDireccion.Text,
dtpFechaNanimiento.Value);
26.
27.if (id > 0)
28.{
29.MessageBox.Show(string.Format("El registro se ha insertado
correctamente. Id : {0}", id));
30.txtId.Text = Convert.ToString(id);
31.}
32.}
33.}
34.
35.private int Insert(string nombre, string direccion, DateTime
fechaNacimiento)
36.{
37.if (!ValidateForm())
38.return 0;
39.
40.string sql = @"INSERT INTO Contactos (NombreCompleto
41.,Direccion
42.,FechaNacimiento)
43.VALUES (@Nombre,
44.@Direccion,
45.@FechaNacimiento)
46.SELECT SCOPE_IDENTITY()";
47.
48.
49.using (SqlConnection conn
= newSqlConnection(ConfigurationManager.ConnectionStrings["default"].ToSt
ring()))
50.{
51.
52.SqlCommand command = new SqlCommand(sql, conn);
53.command.Parameters.AddWithValue("Nombre", nombre);
54.command.Parameters.AddWithValue("Direccion", direccion);
55.command.Parameters.AddWithValue("FechaNacimiento", fechaNacimiento);
56.
57.conn.Open();
58.
59.return Convert.ToInt32(command.ExecuteScalar());
60.
61.}
62.}
[VB.NET]
01.Private Sub btnGuardar_Click(sender As Object, e As EventArgs)
02.'
03.' Validaciones
04.'
05.Dim _Id As Integer = 0
06.If Not String.IsNullOrEmpty(txtId.Text) Then
07.If Not Integer.TryParse(txtId.Text, _Id) Then
08.MessageBox.Show("El Id debe ser un valor numerico")
09.Return
10.End If
11.End If
12.
13.If Exists(_Id) Then
14.Dim result As Boolean = Update(_Id, txtNombre.Text, txtDireccion.Text,
dtpFechaNanimiento.Value)
15.
16.If result Then
17.MessageBox.Show("El registro se ha actualizado correctamente.")
18.End If
19.Else
20.Dim idObtenido As Integer = Insert(txtNombre.Text, txtDireccion.Text,
dtpFechaNanimiento.Value)
21.
22.If idObtenido > 0 Then
23.MessageBox.Show(String.Format("El registro se ha insertado
correctamente. Id : {0}", idObtenido))
24.txtId.Text = Convert.ToString(idObtenido)
25.End If
26.End If
27.End Sub
28.
29.Private Function Insert(nombre As String, direccion As String,
fechaNacimiento AsDateTime) As Integer
30.If Not ValidateForm() Then
31.Return 0
32.End If
33.
34.Dim sql As String = "INSERT INTO Contactos (NombreCompleto" & _
35.",Direccion" & _
36.",FechaNacimiento)" & _
37."VALUES (@Nombre, " & _
38."@Direccion, " & _
39."@FechaNacimiento)" & _
40."SELECT SCOPE_IDENTITY()"
41.
42.
43.Using
conn As NewSqlConnection(ConfigurationManager.ConnectionStrings("default")
.ToString())
44.
45.Dim command As New SqlCommand(sql, conn)
46.command.Parameters.AddWithValue("Nombre", nombre)
47.command.Parameters.AddWithValue("Direccion", direccion)
48.command.Parameters.AddWithValue("FechaNacimiento", fechaNacimiento)
49.
50.conn.Open()
51.
52.
53.Return Convert.ToInt32(command.ExecuteScalar())
54.End Using
55.End Function
Como se observa en el cdigo el principal cambio se lo lleva al consulta SQL, en donde
se combinan dos consultas en una.
Por medio de mtodo ExecuteScalar() del SqlCommand se realizaran las dos
operaciones, ejecutar la consulta de INSERT y al mismo tiempo devolver el valor nico
del SELECT.
Por ultimo se lo pasa el id obtenido al evento en al presentacin para que muestre el id
generado en pantalla.

2 Obtener Id en consultas separadas

Un problema con la tcnica anterior es que si por alguna razn el INSERT no realiza la
operacin de forma correcta, puede haber problemas con el id que se obtiene.
Esto puede ser extrao pero hay formas de asegurar que solo se obtenga con el id si
es que la operacin anterior se ha realizado de forma correcta.
Mas que nada esta tcnica es til cuando se quiere asegurar o validar que el INSERT
afecto a los registros de forma adecuada.
[C#]
01.private int InsertComandosSeparadas(string nombre, string direccion,
DateTime fechaNacimiento)
02.{
03.if (!ValidateForm())
04.return 0;
05.
06.string sql = @"INSERT INTO Contactos (NombreCompleto
07.,Direccion
08.,FechaNacimiento)
09.VALUES (@Nombre,
10.@Direccion,
11.@FechaNacimiento)";
12.
13.
14.using (SqlConnection conn
= newSqlConnection(ConfigurationManager.ConnectionStrings["default"].ToSt
ring()))
15.{
16.
17.SqlCommand command = new SqlCommand(sql, conn);
18.command.Parameters.AddWithValue("Nombre", nombre);
19.command.Parameters.AddWithValue("Direccion", direccion);
20.command.Parameters.AddWithValue("FechaNacimiento", fechaNacimiento);
21.
22.conn.Open();
23.
24.
25.int rowsAffected = command.ExecuteNonQuery();
26.
27.if (rowsAffected > 0)
28.{
29.string sqlIdentity = "SELECT @@IDENTITY";
30.SqlCommand cmdIdentity = new SqlCommand(sqlIdentity, conn);
31.
32.return Convert.ToInt32(cmdIdentity.ExecuteScalar());
33.}
34.else
35.return -1;
36.
37.
38.}
39.}
[VB.NET]
01.Private Function InsertComandosSeparadas(nombre As String,
direccion As String, fechaNacimiento As DateTime) As Integer
02.If Not ValidateForm() Then
03.Return 0
04.End If
05.
06.Dim sql As String = "INSERT INTO Contactos (NombreCompleto" & _
07.",Direccion" & _
08.",FechaNacimiento)" & _
09."VALUES (@Nombre, " & _
10."@Direccion, " & _
11."@FechaNacimiento)"
12.
13.
14.Using
conn As NewSqlConnection(ConfigurationManager.ConnectionStrings("default")
.ToString())
15.
16.Dim command As New SqlCommand(sql, conn)
17.command.Parameters.AddWithValue("Nombre", nombre)
18.command.Parameters.AddWithValue("Direccion", direccion)
19.command.Parameters.AddWithValue("FechaNacimiento", fechaNacimiento)
20.
21.conn.Open()
22.
23.
24.Dim rowsAffected As Integer = command.ExecuteNonQuery()
25.
26.If rowsAffected > 0 Then
27.Dim sqlIdentity As String = "SELECT @@IDENTITY"
28.Dim cmdIdentity As New SqlCommand(sqlIdentity, conn)
29.
30.Return Convert.ToInt32(cmdIdentity.ExecuteScalar())
31.Else
32.Return -1
33.
34.
35.End If
36.End Using
37.End Function

En le cdigo puede observarse que la primer parte se conserva idntica a la origina, en
donde solo una instruccin de INSERT es declarada, y ejecutada por medio del
ExecuteNonQuery(), este retornara los registros afectados y segn el valor de retorno
se proceder a recuperar el id autonumrico generado.
Hay un cambio que hay que hacer notar y es que en el SELECT se ha cambiado la
tcnica usada para recuperar el id, en este caso se hace uso del @@IDENTITY
Seguramente la pregunta que se harn es porque de este cambio, bien resulta que la
diferencia entre estas instrucciones esta en el mbito en que se ejecutan,
SCOPE_IDENTITY trabaja en el mbito actual, o sea el mbito de la instruccin, si en
este ejemplo usramos esta instruccin obtendramos como resultado un NULL, pues
este debe ser ejecutado en la misma operacin.
En cambio @@IDENTY no es afectado por aun mbito especifico, puede ser consultado
luego de haber realizado la operacin de INSERT en una operacin distinta. Algo que
haya que marcar es que @@IDENTITY puede tener problemas ya que al no trabajar en
un mbito determinado puede ser afectada por otras operaciones, si es que se realizan
acciones con varias tablas.
@@IDENTITY
SCOPE_IDENTITY

3 Obtener Id desde Stored Procedure

En este caso se analizara como obtener el id generado por la tabla, en donde la
operacion de actualizacin esta dentro de un Stored Procedure, para esto se requerirn
algunos cambios.

[C#]
01.private int InsertStoredprocedure(string nombre, string direccion,
DateTime fechaNacimiento)
02.{
03.if (!ValidateForm())
04.return 0;
05.
06.using (SqlConnection conn
= newSqlConnection(ConfigurationManager.ConnectionStrings["default"].ToSt
ring()))
07.{
08.conn.Open();
09.
10.SqlCommand command = new SqlCommand("sp_ContactoInsert", conn);
11.command.CommandType = CommandType.StoredProcedure;
12.
13.SqlParameter paramId = new SqlParameter("Id", SqlDbType.Int);
14.paramId.Direction = ParameterDirection.Output;
15.command.Parameters.Add(paramId);
16.
17.command.Parameters.AddWithValue("Nombre", nombre);
18.command.Parameters.AddWithValue("Direccion", direccion);
19.command.Parameters.AddWithValue("FechaNacimiento", fechaNacimiento);
20.
21.int rowsAffected = command.ExecuteNonQuery();
22.
23.if (rowsAffected > 0)
24.{
25.return Convert.ToInt32(command.Parameters["Id"].Value);
26.}
27.else
28.return -1;
29.
30.
31.}
32.}
[VB.NET]
01.Private Function InsertStoredProcedure(nombre As String,
direccion As String, fechaNacimiento As DateTime) As Integer
02.If Not ValidateForm() Then
03.Return 0
04.End If
05.
06.Using
conn As NewSqlConnection(ConfigurationManager.ConnectionStrings("default")
.ToString())
07.conn.Open()
08.
09.Dim command As New SqlCommand("sp_ContactoInsert", conn)
10.command.CommandType = CommandType.StoredProcedure
11.
12.Dim paramId As New SqlParameter("Id", SqlDbType.Int)
13.paramId.Direction = ParameterDirection.Output
14.command.Parameters.Add(paramId)
15.
16.command.Parameters.AddWithValue("Nombre", nombre)
17.command.Parameters.AddWithValue("Direccion", direccion)
18.command.Parameters.AddWithValue("FechaNacimiento", fechaNacimiento)
19.
20.Dim rowsAffected As Integer = command.ExecuteNonQuery()
21.
22.If rowsAffected > 0 Then
23.Return Convert.ToInt32(command.Parameters("Id").Value)
24.Else
25.Return -1
26.End If
27.
28.End Using
29.
30.End Function
[Stored Procedure]
01.ALTER PROCEDURE dbo.sp_ContactoInsert
02.
03.@Id int OUTPUT,
04.@Nombre varchar(50),
05.@Direccion varchar(50),
06.@FechaNacimiento DateTime
07.
08.AS
09.INSERT INTO Contactos (NombreCompleto
10.,Direccion
11.,FechaNacimiento)
12.VALUES (@Nombre,
13.@Direccion,
14.@FechaNacimiento);
15.
16.
17.SELECT @Id = SCOPE_IDENTITY()
18.
19.RETURN

En el cdigo se han quitados todas las consulta reemplazndolo por el nombre del
stored procedure.
En este caso se hace uso de un parmetro que actuara como output para el valor
generado dentro del Stored procedure, el cual ser recuperado luego de la ejecucin
de la instruccin.
[C#]

[VB.NET]

Publicado por Leandro Tuttini en 13:06 22 comentarios:
Etiquetas: ADO.NET, C#, VB.NET
martes, 19 de enero de 2010
[ADO.NET] Parte 5 Operaciones CRUD

Introduccin

El objetivo de este articulo ser el de demostrar con un ejemplo simple como hacer
uso de ado.net para trabajar de forma simple con los datos, realizando operacin de
CRUD (Create, Read, Update and Delete) .
Si bien esta aplicacin de ejemplo hace uso del cdigo desarrollado directamente en el
propio formulario, se vera que el uso de funciones en la estructurada ordena el cdigo
dejndolo mas legible, permitiendo adems mover la funcionalidad de lugar si en el
futuro hiciera falta sin afectar el funcionamiento.
La aplicacin de ejemplo solo cuenta con un formularios, que observaran en esta
imagen


1 Obtener informacin

Si se analiza el cdigo se vera que es por medio de ingreso de un id valido en el campo
que corresponde y mediante la accin de la tecla Enter se realiza la bsqueda.
[C#]
01.private void txtId_KeyPress(object sender, KeyPressEventArgs e)
02.{
03.if((int)e.KeyChar == (int)Keys.Enter)
04.{
05.//
06.// Validaciones
07.//
08.errProvider.SetError(txtId, "");
09.
10.int Id = 0;
11.if (!int.TryParse(txtId.Text, out Id))
12.{
13.errProvider.SetError(txtId, "El Id debe ser un valor numerico");
14.return;
15.}
16.
17.if (!Exists(Id))
18.{
19.errProvider.SetError(txtId,"El Id ingresado no existe.");
20.return;
21.}
22.
23.Obtener(Id);
24.}
25.
26.}
27.
28.private void Obtener(int Id)
29.{
30.string sql = @"SELECT Id
31.,NombreCompleto
32.,Direccion
33.,FechaNacimiento
34.FROM Contactos
35.WHERE Id = @Id";
36.
37.
38.using (SqlConnection conn
= newSqlConnection(ConfigurationManager.ConnectionStrings["default"].ToSt
ring()))
39.{
40.
41.SqlCommand command = new SqlCommand(sql, conn);
42.command.Parameters.AddWithValue("Id", Id);
43.
44.conn.Open();
45.
46.SqlDataReader reader = command.ExecuteReader();
47.
48.if (reader.Read())
49.{
50.txtNombre.Text = Convert.ToString(reader["NombreCompleto"]);
51.txtDireccion.Text = Convert.ToString(reader["Direccion"]);
52.dtpFechaNanimiento.Value =
Convert.ToDateTime(reader["FechaNacimiento"]);
53.}
54.
55.}
56.}
57.
58.private bool Exists(int Id)
59.{
60.string sql = @"SELECT COUNT(*)
61.FROM Contactos
62.WHERE Id = @Id";
63.
64.
65.using (SqlConnection conn
= newSqlConnection(ConfigurationManager.ConnectionStrings["default"].ToSt
ring()))
66.{
67.
68.SqlCommand command = new SqlCommand(sql, conn);
69.command.Parameters.AddWithValue("Id", Id);
70.
71.conn.Open();
72.
73.int count = Convert.ToInt32(command.ExecuteScalar());
74.
75.if (count == 0)
76.return false;
77.else
78.return true;
79.
80.}
81.}
[VB.NET]
01.Private Sub txtId_KeyPress(ByVal sender As Object, ByVal e As KeyPressEve
ntArgs)
02.
03.If AscW(e.KeyChar) = CInt(Keys.Enter) Then
04.'
05.' Validaciones
06.'
07.errProvider.SetError(txtId, "")
08.
09.Dim Id As Integer = 0
10.If Not Integer.TryParse(txtId.Text, Id) Then
11.errProvider.SetError(txtId, "El Id debe ser un valor numerico")
12.Return
13.End If
14.
15.If Not Exists(Id) Then
16.errProvider.SetError(txtId, "El Id ingresado no existe.")
17.Return
18.End If
19.
20.Obtener(Id)
21.End If
22.
23.End Sub
24.
25.Private Sub Obtener(Id As Integer)
26.Dim sql As String = "SELECT Id" & _
27.",NombreCompleto" & _
28.",Direccion" & _
29.",FechaNacimiento " & _
30."FROM Contactos " & _
31."WHERE Id = @Id"
32.
33.
34.Using
conn As NewSqlConnection(ConfigurationManager.ConnectionStrings("default")
.ToString())
35.
36.Dim command As New SqlCommand(sql, conn)
37.command.Parameters.AddWithValue("Id", Id)
38.
39.conn.Open()
40.
41.Dim reader As SqlDataReader = command.ExecuteReader()
42.
43.If reader.Read() Then
44.txtNombre.Text = Convert.ToString(reader("NombreCompleto"))
45.txtDireccion.Text = Convert.ToString(reader("Direccion"))
46.dtpFechaNanimiento.Value =
Convert.ToDateTime(reader("FechaNacimiento"))
47.
48.End If
49.End Using
50.End Sub
51.
52.Private Function Exists(Id As Integer) As Boolean
53.Dim sql As String = "SELECT COUNT(*) " & _
54."FROM Contactos " & _
55."WHERE Id = @Id"
56.
57.
58.Using
conn As NewSqlConnection(ConfigurationManager.ConnectionStrings("default")
.ToString())
59.
60.Dim command As New SqlCommand(sql, conn)
61.command.Parameters.AddWithValue("Id", Id)
62.
63.conn.Open()
64.
65.Dim count As Integer = Convert.ToInt32(command.ExecuteScalar())
66.
67.If count = 0 Then
68.Return False
69.Else
70.Return True
71.
72.End If
73.End Using
74.End Function
En esta seccin de cdigo se observara la recuperacin de una entidad en base al id
ingresado por el usuario.
En el evento KeyPress del textbox que presenta al Id se detecta la presin de la tecla
Enter como medio para indicar la bsqueda de un contacto.
Entre las validaciones a realizar se verifica que el id ingresado sea numrico, tambin
se valida que el registro exista en la base de datos, para ello es que se realiza la
primer consulta que esta encapsulada en la funcin Exists(), esta tomara el id
ingresado y ejecutara una consulta que devolver el numero de registros que coincidan
en este caso con el id ingresado, si el valor es cero entonces el registro no existe.
El mtodo ExecuteScalar() del objeto SqlCommand es ideal para estos casos ya que
devolver el valor del primer registro y la primer columna, como en este caso solo hay
un valor pues se hizo uso de la funcin SQL Count() devolver dato simple.
Una vez validada la existencia se procede a recuperar el registro, para ello la funcin
de Obtener() cumplir la misin, requiriendo que se le pase como parmetro el id del
registro a obtener
Como se observa este tiene una estructura similar a la Exists() solo que no usa el
ExcecuteScalar(), sino que obtiene un SqlReader, usando ExecuteReader() del objeto
SqlCommand.
En este caso se sabe con anticipacin que solo ser devuelto un registro no hace falta
hacer un loop por cada registro, por lo general se utiliza la sentencia while, en este
caso el if cumple la funcin perfectamente para posicionar el cursor del reader a la
primer posicin, y poder realizar la lectura, entonces el if cumple bsicamente dos
funciones:
- permite validad que hay registros que leer, si por algn fallo no hubiera registro al
llegar al if pasara por false.
- al ejecutar el Read() del objeto SqlReader, posiciona el cursos para su lectura
Por ultimo se iguala el valor de cada campo de la consulta, realizando la conversin de
tipos y asignadla a los respectivos controles.
Como se habr observado hasta aqu y tambin se notaran en los ejemplos siguientes,
los pasos para usar los objetos de ado.net son bastante repetitivos:
1- Se crea un objeto SqlConnection para establecer la conexin hacia la base de datos
2- Se crea el objeto SqlCommand, para establecer la consulta que se realizara, y se le
asignan a este los parmetros si es que hacen falta
3- en este punto existir un bifurcacin
3a- Si se usa un DataReader, se podr ejecutar directamente mediante el
ExecuteReader()
3b- Si se usa un DataSet o DataTable, ser necesario utilizar un SqlDataAdapter, para
realizar el Fill() del objeto a cargar con los datos provenientes de la consulta.

2 - Insertar nuevo registro

La operacin de insertar registro tiene algunas particularidades que necesitas ser
detalladas.
Tanto la operacin de insertar o actualizar ser ejecutada mediante el mismo botn a
nivel de interfaz del usuario, para ello es que se identifica si el id que se define existe o
no (usando la funcin Exists(), antes comentada), esto podr ser visto en el evento
Click del botn Guardar.
El primer punto que hay que aclarar es que en este primer ejemplo no se hace uso de
un campo autonumrico (o Identity) para el id de la tabla. Es por ello que se deber
obtener por medio de cdigo cual ser el prximo numero identificador a utilizar.
Para esta operacin es que existe la funcin MaxId(), la cual hace uso de otra funcin
SQL, en este caso MAX() que retornada el valor mximo existente en la tabla para un
determinado campo que indiquemos. En este caso por tratarse de un valor simple,
nuevamente se usa el ExecuteScalar() del SqlCommand.
[C#]
01.private void btnGuardar_Click(object sender, EventArgs e)
02.{
03.//
04.// Validaciones
05.//
06.int Id = 0;
07.if (!string.IsNullOrEmpty(txtId.Text))
08.{
09.if (!int.TryParse(txtId.Text, out Id))
10.{
11.MessageBox.Show("El Id debe ser un valor numerico");
12.return;
13.}
14.}
15.
16.if (Exists(Id))
17.{
18.bool result = Update(Id, txtNombre.Text, txtDireccion.Text,
dtpFechaNanimiento.Value);
19.
20.if (result)
21.MessageBox.Show("El registro se ha actualizado correctamente.");
22.}
23.else
24.{
25.bool result = Insert(txtNombre.Text, txtDireccion.Text,
dtpFechaNanimiento.Value);
26.
27.if (result)
28.MessageBox.Show("El registro se ha insertado correctamente.");
29.}
30.}
31.
32.private bool Insert(string nombre, string direccion, DateTime
fechaNacimiento)
33.{
34.string sql = @"INSERT INTO Contactos (Id
35.,NombreCompleto
36.,Direccion
37.,FechaNacimiento)
38.VALUES (@Id,
39.@Nombre,
40.@Direccion,
41.@FechaNacimiento)";
42.
43.
44.using (SqlConnection conn
= newSqlConnection(ConfigurationManager.ConnectionStrings["default"].ToSt
ring()))
45.{
46.int NextId = MaxId() + 1;
47.
48.SqlCommand command = new SqlCommand(sql, conn);
49.command.Parameters.AddWithValue("Id", NextId);
50.command.Parameters.AddWithValue("Nombre", nombre);
51.command.Parameters.AddWithValue("Direccion", direccion);
52.command.Parameters.AddWithValue("FechaNacimiento", fechaNacimiento);
53.
54.conn.Open();
55.
56.int rowsAffected = command.ExecuteNonQuery();
57.
58.if (rowsAffected > 0)
59.return true;
60.else
61.return false;
62.
63.}
64.}
65.
66.
67.private static int MaxId()
68.{
69.string sql = @"SELECT MAX(Id)
70.FROM Contactos";
71.
72.
73.using (SqlConnection conn
= newSqlConnection(ConfigurationManager.ConnectionStrings["default"].ToSt
ring()))
74.{
75.
76.SqlCommand command = new SqlCommand(sql, conn);
77.
78.conn.Open();
79.
80.return Convert.ToInt32(command.ExecuteScalar());
81.
82.}
83.}

[VB.NET]
01.Private Sub btnGuardar_Click(sender As Object, e As EventArgs)
02.'
03.' Validaciones
04.'
05.Dim Id As Integer = 0
06.If Not String.IsNullOrEmpty(txtId.Text) Then
07.If Not Integer.TryParse(txtId.Text, Id) Then
08.MessageBox.Show("El Id debe ser un valor numerico")
09.Return
10.End If
11.End If
12.
13.If Exists(Id) Then
14.Dim result As Boolean = Update(Id, txtNombre.Text, txtDireccion.Text,
dtpFechaNanimiento.Value)
15.
16.If result Then
17.MessageBox.Show("El registro se ha actualizado correctamente.")
18.End If
19.Else
20.Dim result As Boolean = Insert(txtNombre.Text, txtDireccion.Text,
dtpFechaNanimiento.Value)
21.
22.If result Then
23.MessageBox.Show("El registro se ha insertado correctamente.")
24.End If
25.End If
26.End Sub
27.
28.Private Function Insert(nombre As String, direccion As String,
fechaNacimiento AsDateTime) As Boolean
29.If Not ValidateForm() Then
30.Return False
31.End If
32.
33.Dim sql As String = "INSERT INTO Contactos (Id" & _
34.",NombreCompleto" & _
35.",Direccion" & _
36.",FechaNacimiento)" & _
37."VALUES (@Id, " & _
38."@Nombre, " & _
39."@Direccion, " & _
40."@FechaNacimiento)"
41.
42.
43.Using
conn As NewSqlConnection(ConfigurationManager.ConnectionStrings("default")
.ToString())
44.Dim NextId As Integer = MaxId() + 1
45.
46.Dim command As New SqlCommand(sql, conn)
47.command.Parameters.AddWithValue("Id", NextId)
48.command.Parameters.AddWithValue("Nombre", nombre)
49.command.Parameters.AddWithValue("Direccion", direccion)
50.command.Parameters.AddWithValue("FechaNacimiento", fechaNacimiento)
51.
52.conn.Open()
53.
54.Dim rowsAffected As Integer = command.ExecuteNonQuery()
55.
56.If rowsAffected > 0 Then
57.ClearControls()
58.Return True
59.Else
60.Return False
61.
62.End If
63.End Using
64.
65.End Function
66.
67.Private Function MaxId() As Integer
68.Dim sql As String = "SELECT MAX(Id)" & _
69."FROM Contactos"
70.
71.
72.Using
conn As NewSqlConnection(ConfigurationManager.ConnectionStrings("default")
.ToString())
73.
74.Dim command As New SqlCommand(sql, conn)
75.
76.conn.Open()
77.
78.
79.Return Convert.ToInt32(command.ExecuteScalar())
80.End Using
81.End Function
En el mtodo Insert() se observara que la consulta hace uso de parmetros para
asignar los valores, es por ello que el objeto SqlCommand posee la propiedad
Parameters, y en esta se hace uso de la forma rpida por medio de mtodo
AddWithValue(), definiendo el nombre del parmetro y el valor.
Adems se hace uso de otra del las funciones del SqlCommand el ExecuteNonQuery(),
este es til ante consultas SQL de actualizacin, o sea no retornan un conjunto de
datos. Este mtodo si devolver un valor entero que indicara la cantidad de registros
afectados, si este devuelve cero quiere decir que no se actualizaron registro, en este
ejemplo esto indicara un fallo en la aplicacin ya que siempre al menos un registro
debe ser insertado de forma correcta.

3 Actualizar registro existente

La operacin de actualizacin es bastante similar a la operacin anterior de insert,
salvando la diferencia que cambia completamente la sentencia sql utilizada.
Al igual que con el insert, se hacen uso de parmetros para asignar los valores a la
consulta, salvo que este necesita contar con el id del registro que se quiere actualizar y
ser utilizado en la seccin del WHERE que permitir identificar que registro afectar
con los cambios.
[C#]
01.private void btnGuardar_Click(object sender, EventArgs e)
02.{
03.//
04.// Validaciones
05.//
06.int Id = 0;
07.if (!string.IsNullOrEmpty(txtId.Text))
08.{
09.if (!int.TryParse(txtId.Text, out Id))
10.{
11.MessageBox.Show("El Id debe ser un valor numerico");
12.return;
13.}
14.}
15.
16.if (Exists(Id))
17.{
18.bool result = Update(Id, txtNombre.Text, txtDireccion.Text,
dtpFechaNanimiento.Value);
19.
20.if (result)
21.MessageBox.Show("El registro se ha actualizado correctamente.");
22.}
23.else
24.{
25.bool result = Insert(txtNombre.Text, txtDireccion.Text,
dtpFechaNanimiento.Value);
26.
27.if (result)
28.MessageBox.Show("El registro se ha insertado correctamente.");
29.}
30.}
31.
32.
33.private static bool Update(int id, string nombre, string direccion,
DateTime fechaNacimiento)
34.{
35.
36.string sql = @"UPDATE Contactos SET
37.NombreCompleto = @Nombre
38.,Direccion = @Direccion
39.,[FechaNacimiento] = @FechaNacimiento
40.WHERE Id = @Id";
41.
42.
43.using (SqlConnection conn
= newSqlConnection(ConfigurationManager.ConnectionStrings["default"].ToSt
ring()))
44.{
45.
46.SqlCommand command = new SqlCommand(sql, conn);
47.command.Parameters.AddWithValue("Id", id);
48.command.Parameters.AddWithValue("Nombre", nombre);
49.command.Parameters.AddWithValue("Direccion", direccion);
50.command.Parameters.AddWithValue("FechaNacimiento", fechaNacimiento);
51.
52.conn.Open();
53.
54.int rowsAffected = command.ExecuteNonQuery();
55.
56.if (rowsAffected > 0)
57.return true;
58.else
59.return false;
60.
61.}
62.}

[VB.NET]
01.Private Sub btnGuardar_Click(sender As Object, e As EventArgs)
02.'
03.' Validaciones
04.'
05.Dim Id As Integer = 0
06.If Not String.IsNullOrEmpty(txtId.Text) Then
07.If Not Integer.TryParse(txtId.Text, Id) Then
08.MessageBox.Show("El Id debe ser un valor numerico")
09.Return
10.End If
11.End If
12.
13.If Exists(Id) Then
14.Dim result As Boolean = Update(Id, txtNombre.Text, txtDireccion.Text,
dtpFechaNanimiento.Value)
15.
16.If result Then
17.MessageBox.Show("El registro se ha actualizado correctamente.")
18.End If
19.Else
20.Dim result As Boolean = Insert(txtNombre.Text, txtDireccion.Text,
dtpFechaNanimiento.Value)
21.
22.If result Then
23.MessageBox.Show("El registro se ha insertado correctamente.")
24.End If
25.End If
26.End Sub
27.
28.Private Function Update(id As Integer, nombre As String,
direccion As String, fechaNacimiento As DateTime) As Boolean
29.
30.If Not ValidateForm() Then
31.Return False
32.End If
33.
34.Dim sql As String = "UPDATE Contactos SET " & _
35."NombreCompleto = @Nombre" & _
36.",Direccion = @Direccion" & _
37.",[FechaNacimiento] = @FechaNacimiento " & _
38."WHERE Id = @Id"
39.
40.
41.Using
conn As NewSqlConnection(ConfigurationManager.ConnectionStrings("default")
.ToString())
42.
43.Dim command As New SqlCommand(sql, conn)
44.command.Parameters.AddWithValue("Id", id)
45.command.Parameters.AddWithValue("Nombre", nombre)
46.command.Parameters.AddWithValue("Direccion", direccion)
47.command.Parameters.AddWithValue("FechaNacimiento", fechaNacimiento)
48.
49.conn.Open()
50.
51.Dim rowsAffected As Integer = command.ExecuteNonQuery()
52.
53.If rowsAffected > 0 Then
54.Return True
55.Else
56.Return False
57.
58.End If
59.End Using
60.End Function
4 Eliminar registro

Eliminar un registro es una operacin bastante simple, con solo proporcionar el
identificador para definir la seccin del WHERE en la sintaxis de eliminacin es
suficiente.
En el ejemplo se realiza una operacin previa que valida que id exista, pero tambin se
podra haber obviado esta validacin utilizando el valor proporcionado por el usuario.
[C#]
01.private void btnEliminar_Click(object sender, EventArgs e)
02.{
03.//
04.// Validaciones
05.//
06.errProvider.SetError(txtId, "");
07.
08.int Id = 0;
09.if (!int.TryParse(txtId.Text, out Id))
10.{
11.errProvider.SetError(txtId, "El Id debe ser un valor numerico");
12.return;
13.}
14.
15.if (!Exists(Id))
16.{
17.errProvider.SetError(txtId, "El Id ingresado no existe.");
18.return;
19.}
20.
21.//
22.// Elimino contacto
23.//
24.bool result = Delete(Id);
25.
26.if (result)
27.{
28.MessageBox.Show("El registro se ha eliminado correctamente.");
29.ClearControls();
30.}
31.
32.}
33.
34.public bool Delete(int Id)
35.{
36.string sql = @"DELETE FROM Contactos
37.WHERE Id = @Id";
38.
39.
40.using (SqlConnection conn
= newSqlConnection(ConfigurationManager.ConnectionStrings["default"].ToSt
ring()))
41.{
42.
43.SqlCommand command = new SqlCommand(sql, conn);
44.command.Parameters.AddWithValue("Id", Id);
45.
46.conn.Open();
47.
48.int rowsAffected = command.ExecuteNonQuery();
49.
50.if (rowsAffected > 0)
51.return true;
52.else
53.return false;
54.
55.}
56.}
[VB.NET]
01.Private Sub btnEliminar_Click(sender As Object, e As EventArgs)
02.'
03.' Validaciones
04.'
05.errProvider.SetError(txtId, "")
06.
07.Dim Id As Integer = 0
08.If Not Integer.TryParse(txtId.Text, Id) Then
09.errProvider.SetError(txtId, "El Id debe ser un valor numerico")
10.Return
11.End If
12.
13.If Not Exists(Id) Then
14.errProvider.SetError(txtId, "El Id ingresado no existe.")
15.Return
16.End If
17.
18.'
19.' Elimino contacto
20.'
21.Dim result As Boolean = Delete(Id)
22.
23.If result Then
24.MessageBox.Show("El registro se ha eliminado correctamente.")
25.ClearControls()
26.End If
27.
28.End Sub
29.
30.
31.Public Function Delete(Id As Integer) As Boolean
32.Dim sql As String = "DELETE FROM Contactos " & _
33."WHERE Id = @Id"
34.
35.
36.Using
conn As NewSqlConnection(ConfigurationManager.ConnectionStrings("default")
.ToString())
37.
38.Dim command As New SqlCommand(sql, conn)
39.command.Parameters.AddWithValue("Id", Id)
40.
41.conn.Open()
42.
43.Dim rowsAffected As Integer = command.ExecuteNonQuery()
44.
45.If rowsAffected > 0 Then
46.Return True
47.Else
48.Return False
49.
50.End If
51.End Using
52.End Function
Acerca de los ejemplos

Para poder ejecutar correctamente los ejemplo necesitar Visual Studio 2008 y Sql
Server Express instalado y corriendo localmente.

[C#]

[VB.NET]

Publicado por Leandro Tuttini en 15:43 89 comentarios:
Etiquetas: ADO.NET, C#, VB.NET
mircoles, 2 de diciembre de 2009
[ADO.NET] Excel y Linq (Union)

Introduccin
El objetivo del articulo es demostrar como poder procesar distintos documentos Excel
mediante la utilizacin del provider para Excel de ADO.NET, a su vez las limitaciones
de esta tecnologa es superada por la potencia de Linq, el cual otorga poder de
procesamiento una vez que se tiene la informacin recuperada de los documentos y se
necesita trabajar con los datos.
La idea del ejemplo es poder mostrar una lista de pedidos, informando el numero y
cantidad de tems solicitados. Pero se debe consolidar la lista agrupando y sumando
aquellos numero de pedidos se aparezcan en ambos listados.
Lectura de los documentos Excel
01.DataTable dtExcel1 = new DataTable();
02.DataTable dtExcel2 = new DataTable();
03.
04.using (OleDbConnection cnn
= newOleDbConnection(ConfigurationManager.ConnectionStrings["Excel1"].ToS
tring()))
05.{
06.string sql = @"SELECT pedido,
07.cantidad
08.FROM [Sheet1$]";
09.
10.OleDbCommand command = new OleDbCommand(sql, cnn);
11.
12.OleDbDataAdapter da = new OleDbDataAdapter(command);
13.
14.
15.da.Fill(dtExcel1);
16.
17.}
18.
19.using (OleDbConnection cnn
= newOleDbConnection(ConfigurationManager.ConnectionStrings["Excel2"].ToS
tring()))
20.{
21.string sql = @"SELECT pedido,
22.cantidad
23.FROM [Sheet1$]";
24.
25.OleDbCommand command = new OleDbCommand(sql, cnn);
26.
27.OleDbDataAdapter da = new OleDbDataAdapter(command);
28.
29.
30.da.Fill(dtExcel2);
31.
32.}
Si se analiza el Excel utilizado en le procesamiento se vera que este cuanta con dos
columnas pero en el primer registro de cada una se ha escrito el nombre que se asigna
a cada una de ellas, estos nombres coinciden con los utilizados en la consulta sql que
ser ejecutada.
Para este trabajo se hacen uso de dos dataset los cuales contendrn la informacin
proveniente de cada Excel por separado, que en el prximo paso ser usada para
trabarla y poder adecuarla a la informacin que se necesita visualizar.
Uso de Linq para unir la informacin
01.var query = from item in
02.(from item in dtExcel1.AsEnumerable()
03.select item).Union(from item in dtExcel2.AsEnumerable()
04.select item)
05.group item by Convert.ToInt32(item["pedido"]) into g
06.select new
07.{
08.Pedido = g.Key,
09.Cantidad = g.Sum(x=>Convert.ToInt32(x["cantidad"]))
10.};
La consulta linq realiza varias operaciones para poder adecuar la informacin
proveniente del Excel y que en este punto se encuentra contendida en cada dataset.
El primer paso que realiza es la unin de los dos dataset, o sea la informacin de los
Excel, unificando en un solo grupo de datos los pedidos de ambas listas.
El segundo paso es la realizacin del Group by, el cual permitir unir nmeros de
pedidos que se encuentren repetidos en ambos listados.
Por ultimo crea un nueva entidad annima, es por ellos que utiliza el select new, en
donde define de forma dinmica las propiedades y si contenido.
En este caso solo son dos las propiedades necesarias, el valor Key del objeto que actu
como agrupador y el cual contiene la lista de tems sin repetir del listado. Y la suma de
la cantidad reportada de cada tem agrupado.

[C#]


Publicado por Leandro Tuttini en 19:51 5 comentarios:
Etiquetas: ADO.NET, Linq
domingo, 29 de noviembre de 2009
C# ADO.NET Parte 4 Actualizacin Informacin Ms Access

Introduccin
Este articulo intenta brindar un ejemplo practico de como hacer uso de los objetos de
ADO.NET para poder manipular la informacin de la base de datos, en este caso ser
de Ms Access.
Gran parte de la explicacin se ha realizado en artculos previos
C# ADO.NET Parte 3 Actualizacin Informacin Sql Server
que si bien tratan otra base de datos, se vera que salvo algunos pequeos detalles es
prcticamente idntico.
Es por eso que a medida que se vaya analizando el cdigo 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 Creacin nueva entidad (Insert)
En este cdigo encontraran tambin el mtodo Save() el cual ser el encargado de
determinar si es necesario insertar el registro o simplemente actualizarlos
01.public static ContactoEntity Save(ContactoEntity contacto)
02.{
03.
04.if (string.IsNullOrEmpty(contacto.Nombre))
05.throw new BusinessException(Messages.MSG1002);
06.
07.if (string.IsNullOrEmpty(contacto.Apellido))
08.throw new BusinessException(Messages.MSG1003);
09.
10.if (Exists(contacto))
11.return Update(contacto);
12.else
13.return Insert(contacto);
14.}
Si se analiza el cdigo veras que la funcionalidad que determina si existe la entidad es
idntica a como se programara cuando se hace uso de Sql Server, el nico cambio
radica en que se utiliza los objeto de OleDb
01.private static bool Exists(ContactoEntity contacto)
02.{
03.if (contacto == null)
04.throw new BusinessException(Messages.ERR1001);
05.
06.return Exists(contacto.IdContacto);
07.}
08.
09.private static bool Exists(int Id)
10.{
11.string sql = @"SELECT COUNT(*)
12.FROM Contacto
13.WHERE IdContacto = @Id";
14.
15.
16.using (OleDbConnection conn
= newOleDbConnection(ConfigurationManager.ConnectionStrings["default"].To
String()))
17.{
18.
19.OleDbCommand command = new OleDbCommand(sql, conn);
20.command.Parameters.AddWithValue("Id", Id);
21.
22.conn.Open();
23.
24.int count = Convert.ToInt32(command.ExecuteScalar());
25.
26.if (count == 0)
27.return false;
28.else
29.return true;
30.
31.}
32.}
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 pequeo detalles que hay que aclararlo ya que
puede presentarse problemas en otras circunstancias.
Este se presenta al declarar el parmetro de fecha de nacimiento (lneas 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 mtodo 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.

01.private static ContactoEntity Insert(ContactoEntity contacto)
02.{
03.string sql = @"INSERT INTO Contacto (IdContacto
04.,Nombre
05.,Apellido
06.,FechaNacimiento
07.,Localidad
08.,Calle
09.,Numero)
10.VALUES (@Id,
11.@Nombre,
12.@Apellido,
13.@FechaNacimiento,
14.@Localidad,
15.@Calle,
16.@Numero)";
17.
18.
19.using (OleDbConnection conn
= newOleDbConnection(ConfigurationManager.ConnectionStrings["default"].To
String()))
20.{
21.int NextId = MaxId() + 1;
22.
23.OleDbCommand command = new OleDbCommand(sql, conn);
24.command.Parameters.AddWithValue("Id", NextId);
25.command.Parameters.AddWithValue("Nombre", contacto.Nombre);
26.command.Parameters.AddWithValue("Apellido", contacto.Apellido);
27.
28.OleDbParameter param = new OleDbParameter("FechaNacimiento",
OleDbType.Date);
29.param.Value = contacto.FechaNacimiento;
30.command.Parameters.Add(param);
31.
32.command.Parameters.AddWithValue("Localidad",string.IsNullOrEmpty(conta
cto.Localidad) ? (object)DBNull.Value : contacto.Localidad);
33.command.Parameters.AddWithValue("Calle",string.IsNullOrEmpty(contacto.
Calle) ? (object)DBNull.Value : contacto.Calle);
34.command.Parameters.AddWithValue("Numero", contacto.Numero.HasValue ?
contacto.Numero : (object)DBNull.Value );
35.
36.conn.Open();
37.
38.command.ExecuteNonQuery();
39.
40.contacto.IdContacto = NextId;
41.
42.return contacto;
43.
44.}
45.}
Tambin se veras que la funcin MaxId() que permite recuperar el ultimo id ingresado
no sufre cambio alguno con respecto a utilizado en una base de datos Sql Server
01.private static int MaxId()
02.{
03.string sql = @"SELECT MAX(IdContacto)
04.FROM Contacto";
05.
06.
07.using (OleDbConnection conn
= newOleDbConnection(ConfigurationManager.ConnectionStrings["default"].To
String()))
08.{
09.
10.OleDbCommand command = new OleDbCommand(sql, conn);
11.
12.conn.Open();
13.
14.return Convert.ToInt32(command.ExecuteScalar());
15.
16.}
17.}
2 Actualizacin de la entidad (Update)
En la operacin de actualizacin 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 pensbamos que los nombres
de los parmetros guardaban una conexin, bajo la operacin del actualizacin nos
damos cuenta que no es tan as.
Es por ello que se notara que la creacin de parmetros en este caso el Id ha sido
declarado al final del resto, mientras que en si equivalente para Sql Server podra
haber sido declarado en cualquier posicin.
Esto marca un punto importante durante la actualizacin y es que el nombre sirve para
tener una referencia a que parmetro estamos asignando el valor, pero para el
provider de base de datos OleDb, lo que importa es la posicin del parmetro en
coleccin de Parameters.
Si en este cdigo se declarar el parmetro Id en primer lugar la actualizacin no se
realizara adecuadamente.
01.private static ContactoEntity Update(ContactoEntity contacto)
02.{
03.
04.string sql = @"UPDATE Contacto SET
05.Nombre = @Nombre
06.,Apellido = @Apellido
07.,FechaNacimiento = @FechaNacimiento
08.,Localidad = @Localidad
09.,Calle = @Calle
10.,Numero = @Numero
11.WHERE IdContacto = @Id";
12.
13.
14.using (OleDbConnection conn
= newOleDbConnection(ConfigurationManager.ConnectionStrings["default"].To
String()))
15.{
16.
17.OleDbCommand command = new OleDbCommand(sql, conn);
18.
19.command.Parameters.AddWithValue("Nombre", contacto.Nombre);
20.command.Parameters.AddWithValue("Apellido", contacto.Apellido);
21.
22.OleDbParameter param = new OleDbParameter("FechaNacimiento",
OleDbType.Date);
23.param.Value = contacto.FechaNacimiento;
24.command.Parameters.Add(param);
25.
26.command.Parameters.AddWithValue("Localidad",string.IsNullOrEmpty(conta
cto.Localidad) ? (object)DBNull.Value : contacto.Localidad);
27.command.Parameters.AddWithValue("Calle",string.IsNullOrEmpty(contacto.
Calle) ? (object)DBNull.Value : contacto.Calle);
28.command.Parameters.AddWithValue("Numero", contacto.Numero.HasValue ?
contacto.Numero : (object)DBNull.Value);
29.
30.command.Parameters.AddWithValue("Id", contacto.IdContacto);
31.
32.conn.Open();
33.
34.int rows = command.ExecuteNonQuery();
35.
36.return contacto;
37.
38.}
39.}
3 Eliminacin de la entidad (Delete)
Esta operacin no sufre cambio alguno con respecto a su equivalente en Sql Server,
salvo los objetos de ado.net utilizados.

01.public static void Delete(int Id)
02.{
03.string sql = @"DELETE FROM Contacto
04.WHERE [IdContacto] = @Id";
05.
06.
07.using (OleDbConnection conn
= newOleDbConnection(ConfigurationManager.ConnectionStrings["default"].To
String()))
08.{
09.
10.OleDbCommand command = new OleDbCommand(sql, conn);
11.command.Parameters.AddWithValue("Id", Id);
12.
13.conn.Open();
14.
15.command.ExecuteNonQuery();
16.
17.}
18.}

[C#]

[VB.NET]

Publicado por Leandro Tuttini en 18:36 26 comentarios:
Etiquetas: ADO.NET, C#, MS Access

Potrebbero piacerti anche