NET
La principal funcin de cualquier aplicacin de base de datos es conectarse a un origen de datos y recuperar los datos contenidos . Los proveedores de datos de .NET Framework para A !.NET sirven como puente entre una aplicacin y un origen de datos" permiti#ndole e$ecutar comandos y recuperar datos mediante un DataReader o un DataAdapter.
En esta seccin
En esta seccin
utilice el ob$eto !dbc'onnection del proveedor de datos de .NET Framework para ! )'. ,ara conectarse a un origen de datos !racle" utilice el ob$eto !racle'onnection del proveedor de datos de .NET Framework para ! )'. ,ara almacenar y recuperar de forma segura cadenas de cone&in" vea ,roteger cadenas de cone&in.
Cierre de conexiones
1ecomendamos cerrar siempre la cone&in cuando termine de utili%arla" para que la cone&in pueda regresar al grupo. El bloque Using de 2isual )asic o '3 elimina autom4ticamente la cone&in cuando el cdigo sale del bloque" incluso en el caso de una e&cepcin no controlada. Tambi#n puede utili%ar los m#todos Close o Dispose del ob$eto de cone&in correspondiente al proveedor que est# utili%ando. Es posible que las cone&iones que no se cierran e&pl5citamente no se puedan agregar ni puedan regresar al grupo. ,or e$emplo" una cone&in que se 6a salido del 4mbito pero que no se 6a cerrado e&pl5citamente slo se devolver4 al grupo de cone&in si se 6a alcan%ado el tama7o m4&imo del grupo y la cone&in a8n es v4lida. ,ara obtener m4s informacin" vea escripcin de agrupacin de cone&iones.
Nota
No llame a Close o a Dispose en un objeto Connection, un objeto DataReader o cualquier otro objeto administrado en el mtodo Finalize de la clase. En un finalizador, libere slo los recursos no administrados que pertenezcan directamente a su clase. Si la clase no dispone de recursos no administrados, no incluya un mtodo Finalize en la definicin de clase. Para obtener ms informacin, vea ecoleccin de elementos no utilizados.
Conexin a SQ Ser!er
El proveedor de datos de .NET Framework para *+L *erver admite un formato de cadena de cone&in que es similar al de !LE cadena" vea 'onnection*tring. El siguiente cdigo de e$emplo demuestra cmo crear y abrir una cone&in a una base de datos *+L *erver ../ o posterior. '3 'opiar cdigo ) 9A !:. ,ara ver los nombres y valores v4lidos de formato de
// Assumes connectionString is a valid connection string. using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); // Do wor !ere. "
Seguridad integrada y ASP.NET La seguridad integrada de *+L *erver 9tambi#n conocida como cone&iones de confian%a: ayuda a proteger las cone&iones a *+L *erver dado que no e&pone el ;d. y la contrase7a de un usuario en la cadena de cone&in y es el m#todo recomendado para autenticar una cone&in. La seguridad integrada utili%a la identidad de seguridad actual" o s5mbolo 9token:" del proceso en e$ecucin" que en aplicaciones de escritorio" es normalmente la identidad del usuario que actualmente 6a iniciado la sesin. La identidad de seguridad para aplicaciones A*,.NET se puede establecer en una de varias opciones diferentes. ,ara comprender me$or la identidad de seguridad que utili%a una aplicacin A*,.NET al establecer una cone&in a *+L *erver" vea *uplantacin de A*,.NET" Aut6entication and A*,.NET ;mpersonation y 'mo( !btener acceso a *+L *erver mediante la seguridad integrada de <indows.
) y a -icrosoft *+L *erver 0. x o anterior 9a trav#s de ) para *+L *erver:" utili%ando el ob$eto OleDbConnection. )" el formato de cadena de cone&in es
*e necesita la palabra clave Proveedor. No se admiten las palabras clave URL" Proveedor remoto y Servidor remoto. )" vea el tema
,ara obtener m4s informacin acerca de las cadenas de cone&in !LE 'onnection*tring.
proveedor de #$E %&. Slo se admiten las propiedades que se pueden proporcionar en la cadena de cone'in para el proveedor de #$E %&. El siguiente cdigo de e$emplo demuestra cmo crear y abrir una cone&in a un origen de datos !LE '3 'opiar cdigo ).
// Assumes connectionString is a valid connection string. using (OleD#Connection connection = new OleD#Connection(connectionString)) { connection.Open(); // Do wor !ere. "
No utilice arc#i!os de !nculo de datos uni!ersal
*e puede proporcionar informacin de cone&in para un ob$eto OleDbConnection en un arc6ivo de v5nculos de datos universal 9= L:" pero conviene evitarlo. Los arc6ivos = L no est4n cifrados y e&ponen la informacin de cadena de cone&in en te&to sin cifrar. =n arc6ivo = L no se puede proteger mediante .NET Framework" ya que se trata de un recurso basado en un arc6ivo e&terno a la aplicacin.
Nota El proveedor de datos de .NE( )rame*or+ para #%&, no se incluye en .NE( )rame*or+ -... Si necesita utilizar el proveedor de datos de .NE( )rame*or+ para #%&, y est utilizando .NE( )rame*or+ -.., puede descar!arlo en en este sitio /eb de 0icrosoft. El espacio de nombres del proveedor de datos de .NE( )rame*or+ para #%&, descar!ado es Microsoft.Data.Odbc. El siguiente cdigo de e$emplo demuestra cmo crear y abrir una cone&in a un origen de datos ! )'. '3 'opiar cdigo
// Assumes connectionString is a valid connection string. using (Od#cConnection connection = new Od#cConnection(connectionString)) { connection.Open(); // Do wor !ere. "
Conexin a un origen de datos Oracle
El proveedor de .NET Framework para !racle proporciona conectividad a or5genes de datos !racle utili%ando el ob$eto OracleConnection.
En el proveedor de datos de .NET Framework para !racle" el formato de cadena de cone&in est4 dise7ado para que coincida lo m4s posible con el del proveedor de !LE !racle'onnection. El siguiente cdigo de e$emplo demuestra cmo crear y abrir una cone&in a un origen de datos !racle. '3 'opiar cdigo ) para !racle 9-* A!1A:. ,ara obtener informacin m4s detallada acerca de OracleConnection" vea la 'lase
// Assumes connectionString is a valid connection string. using (OracleConnection connection = new OracleConnection(connectionString)) { connection.Open(); // Do wor !ere. " OracleConnection nwindConn = new OracleConnection($Data Source=%&OracleServer;'ntegrated Securit&=&es;$); nwindConn.Open();
e&word(=value; e&word)=value
Los espacios se omiten y las palabras clave no distinguen entre may8sculas y min8sculas" si bien los valores podr5an presentar esta distincin" seg8n la diferenciacin entre may8sculas y min8sculas del origen de datos. ,ara incluir valores que contengan un punto y coma" un car4cter de comilla sencilla o un car4cter de comilla doble" el valor debe colocarse entre comillas dobles. La sinta&is v4lida de cadena de cone&in var5a seg8n el proveedor y 6a evolucionado a lo largo de los a7os desde las primeras A,; como ! )'. El proveedor de datos de .NET Framework para *+L *erver incorpora muc6os elementos de la sinta&is antigua y" por lo general" es m4s tolerante con la sinta&is com8n de cadena de cone&in. ,ara obtener m4s informacin acerca de las palabras clave de cadena de cone&in de los proveedores de datos .NET" vea 'onnection*tring" 'onnection*tring" 'onnection*tring y 'onnection*tring.
*i se establece en true o yes" permitir4 obtener informacin de seguridad confidencial" incluidos el ;d. de usuario y la contrase7a" de la cone&in una ve% que est# abierta. *i es necesario proporcionar un ;d. de usuario y una contrase7a al reali%ar una cone&in" estar4 completamente protegido si esa informacin se descarta una ve% que se 6aya utili%ado para abrir la cone&in> esto sucede cuando Persist Security Info se establece como false o no. Esto es especialmente importante si proporciona una cone&in abierta a un origen que no sea de confian%a o guarda la informacin de cone&in en disco. *i se mantiene el valor Persist Security Info como false" se contribuye a que un origen que no sea de confian%a no tenga acceso a la informacin de seguridad confidencial de la cone&in y contribuye" adem4s" a que no se guarde en el disco ning8n tipo de informacin de seguridad confidencial que contenga informacin de su cadena de cone&in.
,rusted-Connection=&es;
Creacin de cadenas de conexin
'ada uno de los proveedores de datos de .NET Framework proporciona una clase generadora de cadenas de cone&in con establecimiento infle&ible de tipos que se 6ereda de b'onnection*tring)uilder. Los generadores de cadenas de cone&in permiten a los programadores crear mediante programacin cadenas de cone&in sint4cticamente correctas basadas en la informacin introducida por el usuario" as5 como anali%ar y reconstruir cadenas de cone&in e&istentes. ,ara obtener m4s informacin" vea *ql'onnection*tring)uilder" !le b'onnection*tring)uilder" !dbc'onnection*tring)uilder y !racle'onnection*tring)uilder.
La cadena de cone&in se puede almacenar en el arc6ivo de configuracin en el elemento !connectionStrings". Las cadenas de cone&in se almacenan como pares de clave y valor" donde el nombre se puede utili%ar para buscar el valor almacenado en el atributo connectionString en tiempo de e$ecucin. En el siguiente e$emplo de arc6ivo de configuracin" se muestra una cadena de cone&in llamada atabase'onnection que 6ace referencia a una cadena de cone&in que se conecta a una instancia local de *+L *erver. 'opiar cdigo
Nota de seguridad #pcionalmente, puede utilizar confi!uracin prote!ida para cifrar las cadenas de cone'in almacenadas en arc1ivos de confi!uracin. 2ea ,ifrar informacin de confi!uracin mediante una confi!uracin prote!ida, Encryptin! and %ecryptin! ,onfi!uration Sections y (utorial3 ,ifrar la informacin de confi!uracin mediante la confi!uracin prote!ida. Ejemplo En el siguiente e$emplo se recupera la cadena de cone&in del arc6ivo de configuracin pasando el nombre de la dic6a cadena al 'onfiguration-anager" que devuelve un ob$eto ConnectionStringSettings. La propiedad ConnectionString sirve para mostrar el valor. '3 'opiar cdigo
using S&stem; using S&stem.Con+iguration; class *rogram { static void %ain() { ConnectionStringSettings settings; settings = Con+iguration%anager.ConnectionStrings2$Data#aseConnection$3; i+ (settings 4= null) { Console.5rite6ine(settings.ConnectionString); " " "
Cadenas de conexin S+lClient
La propiedad ConnectionString de una *ql'onnection permite obtener o establecer una cadena de cone&in para una base de datos *+L *erver ../ o posterior. *i necesita conectarse a una versin anterior de *+L *erver" deber4 utili%ar el proveedor de datos .NET para !le b. Sintaxis de cadena de conexin S l!lient La sinta&is para conectarse a una base de datos *+L *erver es fle&ible. En cada una de las siguientes formas de sinta&is se utili%ar4 seguridad integrada para conectarse a la base de datos
Adventure#or$s en un servidor local. Especifique siempre el servidor por el nombre o por la palabra clave (local). 'opiar cdigo
$*ersist Securit& 'n+o=0alse;'ntegrated Securit&=true;'nitial Catalog=Adventure5or s;Server=%SS76($ $*ersist Securit& 'n+o=0alse;'ntegrated Securit&=SS*';data#ase=Adventure5or s;server=(local)$ $*ersist Securit& 'n+o=0alse;,rusted-Connection=,rue;data#ase=Adventure5or s;server=(local)$
,ara for%ar un protocolo" agregue uno de los siguientes prefi$os(
Server=%&SqlServer<%SS76(;$
!onfiguracin de la "i"lioteca de red =tilice esta sinta&is para conectarse mediante una direccin ;," donde la biblioteca de red es <in@? <insock T',A;, y BC@@ es el puerto que se va a utili%ar 9el predeterminado:. 'opiar cdigo
La propiedad ConnectionString de una !le b'onnection permite obtener o establecer una cadena de cone&in para un origen de datos !LE )" como -icrosoft Access o *+L *erver 0.E o anterior. En *+L *erver ../ o superior" utilice una S%lConnection. Sintaxis de cadena de conexin #le$" ,ara una cadena de cone&in OleDbConnection e&istente" debe proporcionar un nombre de proveedor. La siguiente cadena de cone&in conecta a una base de datos -icrosoft Access mediante el proveedor Fet. Tenga en cuenta que las palabras clave UserID y Password son opcionales si la base de datos no est4 protegida 9el valor predeterminado:. 'opiar cdigo
'opiar cdigo
Evento
Descripcin
InfoMessage Se produce cuando se devuelve un mensaje informativo desde un ori!en de datos. $os mensajes informativos son aquellos procedentes de or"!enes de datos que no inician una e'cepcin. StateC ange Se produce cuando cambia el estado del objeto Connection.
El evento Info(essage recibe un ob$eto ;nfo-essageEventArgs que contiene en su propiedad &rrors una coleccin de los mensa$es del origen de datos. ,uede consultar los ob$etos &rror de esa coleccin para conocer el n8mero de error y el te&to del mensa$e" as5 como el origen del error. El proveedor de datos de .NET Framework para *+L *erver incluye asimismo datos acerca de la base de datos" el procedimiento almacenado y el n8mero de l5nea donde se origin el mensa$e. Ejemplo En el e$emplo de cdigo siguiente se muestra cmo se puede agregar un controlador de eventos para el evento Info(essage. '3 'opiar cdigo
// Assumes t!at connection represents a SqlConnection o#Ject. connection.'n+o%essage K= new Sql'n+o%essageAventEandler(On'n+o%essage); protected static void On'n+o%essage( o#Ject sender9 Sql'n+o%essageAventArgs args) { +oreac! (SqlArror err in args.Arrors) { Console.5rite6ine( $,!e {=" !as received a severit& {("9 state {)" error num#er {?"<n$ K $on line {>" o+ procedure {L" on server {M"8<n{N"$9 err.Source9 err.Class9 err.State9 err.1um#er9 err.6ine1um#er9 err.*rocedure9 err.Server9 err.%essage); " "
Controlar errores como &n'o,essages
Normalmente" el evento Info(essage slo se activa para mensa$es informativos y de advertencia enviados desde el servidor. *in embargo" cuando se produce un error real" se detiene la e$ecucin de los m#todos &'ecute)on*uery o &'ecuteReader que iniciaron la operacin del servidor y se inicia una e&cepcin. *i desea seguir procesando el resto de las instrucciones de un comando" independientemente de los errores producidos en el servidor" estable%ca la propiedad Fire;nfo-essageEvent!n=serErrors de S%lConnection como true. e esta forma" la cone&in activa el evento Info(essage para errores" en lugar de iniciar una e&cepcin e interrumpir el procesamiento. La aplicacin cliente puede controlar el evento y reaccionar ante las situaciones de error.
Nota $os errores con un nivel de !ravedad de -4, como m"nimo, que 1acen que el servidor interrumpa el procesamiento de comandos, deben controlarse como e'cepciones. En este caso, se inicia una e'cepcin, independientemente del modo en que se controle el error en el evento InfoMessage.
// Assumes connection represents a SqlConnection o#Ject. connection.StateC!ange K= new StateC!angeAventEandler(OnStateC!ange); protected static void OnStateC!ange(o#Ject sender9 StateC!angeAventArgs args) { Console.5rite6ine( $,!e current Connection state !as c!anged +rom {=" to {(".$9 args.OriginalState9 args.CurrentState); "
cmo des6abilitar la agrupacin reempla%ando los valores predeterminados del servicio del
,ara obtener m4s informacin acerca de la agrupacin de cone&iones ! )'" vea !LE ,rogrammerKs 1eference en la biblioteca -* N.
no administrados que pertene%can directamente a su clase. *i la clase no dispone de recursos no administrados" no incluya un m#todo /inali0e en la definicin de clase. ,ara obtener m4s informacin" vea 1ecoleccin de elementos no utili%ados. !ompati"ilidad con transacciones Las cone&iones se e&traen del grupo y se asignan en funcin del conte&to de transaccin. Es necesario que el subproceso solicitante y la cone&in asignada coincidan. ,or lo tanto" cada grupo de cone&in se divide realmente en cone&iones que no tienen asociado ning8n conte&to de transaccin y en N subdivisiones" cada una de las cuales contiene cone&iones con un conte&to de transaccin particular. 'uando se cierra una cone&in" se libera de nuevo en el grupo y en la subdivisin adecuada en funcin de su conte&to de transaccin. ,or lo tanto" puede cerrar la cone&in sin generar un error" incluso aunque a8n 6aya pendiente una transaccin distribuida. Esto le permite confirmar o anular la transaccin distribuida m4s adelante. !ontrol de la agrupacin de conexiones con pala"ras clave de cadena de conexin La propiedad 'onnection*tring del ob$eto OracleConnection admite pares de clave y valor de cadena de cone&in que se pueden utili%ar para a$ustar el comportamiento de la lgica de agrupacin de cone&iones. En la siguiente tabla se describen los valores ConnectionString que puede utili%ar para a$ustar el comportamiento de agrupacin de cone&iones.
Default Descripcin . ,uando una cone'in se devuelve al !rupo, su 1ora de creacin se compara con la 1ora actual y, si ese marco temporal 5en se!undos6 e'cede el valor especificado por Connection "ifeti!e, la cone'in se destruye. Esto resulta de utilidad en confi!uraciones a!rupadas para forzar el equilibrio de car!a entre un servidor en ejecucin y uno que acaba de conectarse. 7n valor de cero 5.6 1ar que las cone'iones a!rupadas ten!an el tiempo de espera m'imo. ,uando es true, el concentrador inscribe automticamente la cone'in en el conte'to de transaccin actual del subproceso de creacin, si e'iste un conte'to de transaccin. El n9mero m'imo de cone'iones permitido en el !rupo. El n9mero m"nimo de cone'iones mantenido en el !rupo. ,uando es true, la cone'in se e'trae del !rupo adecuado o, si es necesario, se crea y a!re!a al !rupo correcto.
/e'erencia
b'onnection escribe la clase DbConnection" as5 como todos sus miembros. OdbcConnection escribe la clase OdbcConnection" as5 como todos sus miembros.
OleDbConnection escribe la clase OleDbConnection" as5 como todos sus miembros. OracleConnection escribe la clase OracleConnection" as5 como todos sus miembros. S%lConnection escribe la clase S%lConnection" as5 como todos sus miembros.
En esta seccin
E$ecutar un comando
El ob$eto Command e&pone varios m#todos &'ecute que puede utili%ar para llevar a cabo la accin deseada. 'uando los resultados se devuelven en forma de secuencia de datos" puede utili%ar &'ecuteReader para devolver un ob$eto DataReader. &'ecuteScalar sirve para devolver un valor *ingleton. &'ecute)on*uery se utili%a para e$ecutar comandos que no devuelven filas. Al utili%ar el ob$eto Command con un procedimiento almacenado" puede establecer la propiedad Command1ype del ob$eto Command para que tenga el valor StoredProcedure. 'uando Command1ype tiene el valor StoredProcedure" puede utili%ar la propiedad Parameters del ob$eto Command para tener acceso a los par4metros de entrada y de salida y a los valores devueltos. ,uede acceder a la propiedad Parameters independientemente del m#todo &'ecute llamado. *in embargo" al llamar a &'ecuteReader" no es posible el acceso a los valores devueltos y los par4metros de salida 6asta que se cierra DataReader. En el siguiente e$emplo de cdigo se muestra cmo crear un ob$eto *ql'ommand para devolver una lista de categor5as de la base de datos de e$emplo )ort+wind de *+L *erver.
E$emplo
// nwindConn is assumed to #e a valid SqlConnection o#Ject. SqlCommand command = new SqlCommand( $SA6AC, Categor&'D9 Categor&1ame 0FO% d#o.Categories$9 nwindConn);
!ontadores de rendimiento para comandos El proveedor de datos de .NET Framework para *+L *erver agrega un contador de rendimiento que permite detectar problemas intermitentes relacionados con errores en la e$ecucin de comandos. Al tener acceso al contador S%lClient2 1otal 3 failed commands4 del -onitor de sistema" incluido en el ob$eto de rendimiento )&1 CLR Data" puede conocer el n8mero total de errores producidos por cualquier causa al e$ecutar comandos.
Nota :l utilizar el proveedor de datos de .NE( )rame*or+ para los contadores de rendimiento de S;$ Server conjuntamente con aplicaciones :SP.NE(, se recomienda utilizar slo la instancia %&lobal. ,omo resultado, el valor devuelto por el contador de rendimiento es la suma de los valores de los contadores de todas las aplicaciones :SP.NE(.
Nota El #dbc,ommand requiere que el usuario proporcione la sinta'is de llamada ,:$$ de #%&, completa al llamar a un procedimiento almacenado.
E$emplo
'3 'opiar cdigo
// Assumes t!at connection is a valid SqlConnection o#Ject. SqlCommand salesCommand = new SqlCommand($SalesB&Categor&$9 connection); salesCommand.Command,&pe = Command,&pe.Stored*rocedure; Sql*arameter parameter = salesCommand.*arameters.Add( $PCategor&1ame$9 SqlD#,&pe.1QarC!ar9 (L); parameter.Qalue = $Beverages$; connection.Open(); SqlDataFeader reader = salesCommand.ACecuteFeader(); Console.5rite6ine(
${="9 {("$9 reader.Ret1ame(=)9 reader.Ret1ame(()); w!ile (reader.Fead()) { Console.5rite6ine(${="9 S{("$9 reader.RetString(=)9 reader.RetDecimal(()); " reader.Close(); connection.Close();
=n ob$eto Parameter se puede crear mediante el constructor Parameter o al llamar al m#todo Add de la coleccin Parameters de Command. Parameters Add acepta como entrada argumentos del constructor o cualquier ob$eto Parameter ya e&istente. Al establecer como una referencia nula el valor de 5alue de un ob$eto Parameter" debe utili%ar D-)ull 5alue. En el caso de par4metros que no sean de entrada 9Input:" debe asignar a la propiedad ParameterDirection un valor que especifique cu4l es el tipo de par4metro( InputOutput" Output o Return5alue. En el e$emplo siguiente se muestra la diferencia en la creacin de par4metros Input" Output y Return5alue para los distintos proveedores.
E$emplo de S+lClient
'3 'opiar cdigo
// Assumes t!at connection is a valid SqlConnection o#Ject. SqlCommand command = new SqlCommand($Sample*roc$9 connection); command.Command,&pe = Command,&pe.Stored*rocedure; Sql*arameter parameter = command.*arameters.Add( $FA,:F1-QA6:A$9 SqlD#,&pe.'nt); parameter.Direction = *arameterDirection.FeturnQalue; parameter = command.*arameters.Add( $P'nput*arm$9 SqlD#,&pe.1QarC!ar9 ()); parameter.Qalue = $Sample Qalue$; parameter = command.*arameters.Add( $POutput*arm$9 SqlD#,&pe.1QarC!ar9 )D); parameter.Direction = *arameterDirection.Output; connection.Open(); SqlDataFeader reader = command.ACecuteFeader(); Console.5rite6ine( ${="9 {("$9 reader.Ret1ame(=)9 reader.Ret1ame(()); w!ile (reader.Fead()) { Console.5rite6ine( ${="9 {("$9 reader.Ret'nt?)(=)9 reader.RetString(()); " reader.Close(); connection.Close(); Console.5rite6ine($ POutput*arm8 {="$9 command.*arameters2$POutput*arm$3.Qalue); Console.5rite6ine($FA,:F1-QA6:A8 {="$9 command.*arameters2$FA,:F1-QA6:A$3.Qalue);
E$emplo de OleDb
'3 'opiar cdigo
OleD#Command command = new OleD#Command($Sample*roc$9 connection); command.Command,&pe = Command,&pe.Stored*rocedure; OleD#*arameter parameter = command.*arameters.Add( $FA,:F1-QA6:A$9 OleD#,&pe.'nteger); parameter.Direction = *arameterDirection.FeturnQalue; parameter = command.*arameters.Add( $P'nput*arm$9 OleD#,&pe.QarC!ar9 ()); parameter.Qalue = $Sample Qalue$; parameter = command.*arameters.Add(
$POutput*arm$9 OleD#,&pe.QarC!ar9 )D); parameter.Direction = *arameterDirection.Output; connection.Open(); OleD#DataFeader reader = command.ACecuteFeader(); Console.5rite6ine(${="9 {("$9 reader.Ret1ame(=)9 reader.Ret1ame(()); w!ile (reader.Fead()) { Console.5rite6ine(${="9 {("$9 reader.Ret'nt?)(=)9 reader.RetString(()); " reader.Close(); connection.Close(); Console.5rite6ine($ POutput*arm8 {="$9 command.*arameters2$POutput*arm$3.Qalue); Console.5rite6ine($FA,:F1-QA6:A8 {="$9 command.*arameters2$FA,:F1-QA6:A$3.Qalue);
E$emplo de Odbc
'3 'opiar cdigo
Od#cCommand command = new Od#cCommand( - ${ T = CA66 Sample*roc(T9 T) "$9 connection); command.Command,&pe = Command,&pe.Stored*rocedure; Od#c*arameter parameter = command.*arameters.Add( - $FA,:F1-QA6:A$9 Od#c,&pe.'nt); parameter.Direction = *arameterDirection.FeturnQalue; parameter = command.*arameters.Add( - $P'nput*arm$9 Od#c,&pe.QarC!ar9 ()); parameter.Qalue = $Sample Qalue$; parameter = command.*arameters.Add( $POutput*arm$9 Od#c,&pe.QarC!ar9 )D); parameter.Direction = *arameterDirection.Output; connection.Open(); Od#cDataFeader reader = command.ACecuteFeader(); Console.5rite6ine(${="9 {("$9 reader.Ret1ame(=)9 reader.Ret1ame(()); w!ile (reader.Fead()) { Console.5rite6ine( - ${="9 {("$9 reader.Ret'nt?)(=)9 reader.RetString(()); " reader.Close(); connection.Close(); Console.5rite6ine($ POutput*arm8 {="$9 command.*arameters2$POutput*arm$3.Qalue); Console.5rite6ine($FA,:F1-QA6:A8 {="$9 command.*arameters2$FA,:F1-QA6:A$3.Qalue);
%tili&ar par'metros con S l!ommand Al utili%ar par4metros con *ql'ommand" los nombres de los par4metros agregados a la coleccin ,arameters deben coincidir con los de los marcadores de par4metro del procedimiento almacenado. El proveedor de datos de .NET Framework para *+L *erver trata los par4metros del procedimiento almacenado como par4metros con nombre y busca los marcadores de par4metros que coinciden con sus nombres. El proveedor de datos de .NET Framework para *+L *erver no permite usar el marcador de posicin de signo de interrogacin de cierre 9L: para pasar par4metros a una instruccin *+L o a un procedimiento almacenado. En este caso" debe utili%ar par4metros con nombre" como se muestra en el e$emplo siguiente donde PCustomer'D es el par4metro con nombre. 'opiar cdigo
%tili&ar par'metros con #le$"!ommand o con #d"c!ommand Al utili%ar par4metros con !le b'ommand o con OdbcCommand" el orden de los par4metros agregados a la coleccin Parameters debe coincidir con el de los par4metros definidos en el procedimiento almacenado. El proveedor de datos de .NET Framework para !LE ) y el proveedor de datos de .NET Framework para ! )' consideran a los par4metros de un procedimiento almacenado como marcadores de posicin y aplican los valores de los par4metros en orden. Adem4s" los par4metros de valores devueltos deben ser los primeros que se agreguen a la coleccin Parameters. El proveedor de datos de .NET Framework para !LE ) y el proveedor de datos de .NET
Framework para ! )' no permiten usar par4metros con nombre para pasar par4metros a una instruccin *+L o a un procedimiento almacenado. En este caso" se debe utili%ar el marcador de posicin de signo interrogacin de cierre 9L:" como se muestra en el e$emplo siguiente. 'opiar cdigo
// Assumes t!at connection is a valid SqlConnection o#Ject. SqlCommand salesCommand = new SqlCommand($Sales B& Gear$9 connection); salesCommand.Command,&pe = Command,&pe.Stored*rocedure; connection.Open(); SqlCommandBuilder.Derive*arameters(salesCommand); connection.Close();
utili%ar el ob$eto
El requisito m5nimo para que la generacin autom4tica de comandos funcione correctamente consiste en establecer la propiedad SelectCommand. El esquema de tabla que recupera la propiedad SelectCommand determina la sinta&is de las instrucciones ;N*E1T" =, ATE y generadas autom4ticamente. DbCommand-uilder debe e$ecutar SelectCommand con el ob$eto de poder devolver los metadatos necesarios para construir los comandos *+L ;N*E1T" =, ATE y ELETE. ,or eso es necesario reali%ar un via$e adicional al origen de datos" con el consiguiente efecto adverso en el rendimiento. ,ara me$orar el rendimiento" debe especificar los comandos de forma e&pl5cita" en lugar de utili%ar DbCommand-uilder. SelectCommand debe adem4s devolver al menos una clave principal o columna 8nica. *i no 6ay ninguna" se inicia una e&cepcin InvalidOperation y no se genera ning8n comando. 'uando se asocia con un DataAdapter" DbCommand-uilder genera autom4ticamente las propiedades InsertCommand" UpdateCommand y DeleteCommand del DataAdapter si son referencias nulas. *i ya e&iste alg8n comando Command para una propiedad" se utili%ar4 ese. Las vistas de bases de datos creadas al unir una o varias tablas no se consideran una tabla 8nica de base de datos. En este caso no puede utili%ar DbCommand-uilder para generar comandos autom4ticamente y debe especificarlos de manera e&pl5cita. ,ara obtener informacin sobre cmo especificar comandos de forma e&pl5cita para refle$ar el origen de datos de las actuali%aciones efectuadas en el DataSet" vea Actuali%ar or5genes de datos con ataAdapters. ELETE
,uede ser aconse$able asignar los par4metros de salida a la fila actuali%ada de un DataSet. =na tarea 6abitual consiste en recuperar" a partir del origen de datos" el valor de un campo de identidad de generacin autom4tica o una marca de 6ora. DbCommand-uilder no asigna de forma predeterminada los par4metros de salida a las columnas de una fila actuali%ada. En este caso" debe especificar el comando de forma e&pl5cita. ,ara consultar un e$emplo de asignacin de un campo de identidad de generacin autom4tica a una columna de una fila insertada" vea 1ecuperar valores de identidad o de autonumeracin.
Co!ando InsertCo!!and
Regla <nserta una fila en el ori!en de datos para todas las filas de la tabla con una o*State con el valor :dded. <nserta valores para todas las columnas actualizables, pero no para determinadas columnas como identidades, e'presiones o marcas de 1ora.
'pdateCo!!and :ctualiza filas en el ori!en de datos para todas las filas de la tabla con un valor Ro(State 0odified. :ctualiza los valores de todas las columnas, con e'cepcin de las que no son actualizables, como identidades o e'presiones. :ctualiza todas las filas en las que los valores de columna en el ori!en de datos coinciden con los valores de la columna de clave principal de la fila, siempre que las restantes columnas del ori!en de datos coincidan con los valores ori!inales de la fila. Para obtener ms informacin, vea la seccin =0odelo de simultaneidad optimista para actualizaciones y eliminaciones= de este mismo tema. DeleteCo!!and Elimina filas en el ori!en de datos para todas las filas de la tabla con un valor Ro(State %eleted. Elimina todas las filas en las que los valores de columna coinciden con los valores de la columna de clave principal de la fila, siempre que las restantes columnas del ori!en de datos coincidan con los
valores ori!inales de la fila. Para obtener ms informacin, vea la seccin =0odelo de simultaneidad optimista para actualizaciones y eliminaciones= de este mismo tema.
fila slo se actuali%a cuando contiene todos los valores originales y no 6a sido eliminada del origen de datos. Esto evita que se sobrescriban los datos nuevos. En los casos en que una actuali%acin generada autom4ticamente intenta actuali%ar una fila que 6a sido eliminada o que no contiene los valores originales que se encuentran en el registros y se inicia una e&cepcin ata*et" el comando no tienen ning8n efecto en los )'oncurrencyE&ception. ELETE se e$ecute sin tener en cuenta los valores originales"
// Assumes t!at connection is a valid SqlConnection o#Ject. SqlDataAdapter adapter = new SqlDataAdapter( $SA6AC, ; 0FO% d#o.Customers$9 connection); SqlCommandBuilder #uilder = new SqlCommandBuilder(adapter); #uilder.7uote*re+iC = $2$; #uilder.7uoteSu++iC = $3$; DataSet custDS = new DataSet(); connection.Open(); adapter.0ill(custDS9 $Customers$); // Code to modi+& data in t!e DataSet !ere. // 5it!out t!e SqlCommandBuilder9 t!is line would +ail. adapter.:pdate(custDS9 $Customers$); connection.Close();
,odi'icar SelectCommand
Es posible que se inicie una e&cepcin si modifica el te&to Command1e't de SelectCommand despu#s de generar autom4ticamente los comandos ;N*E1T" =, ATE o ELETE. *i el te&to de SelectCommand Command1e't modificado contiene informacin del esquema que sea inco6erente con la del te&to de SelectCommand Command1e't utili%ado en el momento de la generacin autom4tica de los comandos de insercin" actuali%acin o eliminacin" las futuras llamadas al m#todo DataAdapter Update pueden tratar de tener acceso a columnas que ya no e&istan en la tabla actual a la que 6ace referencia SelectCommand" con lo que se inicia una e&cepcin. ,uede actuali%ar la informacin del esquema que utili%a Command-uilder para generar autom4ticamente los comandos> para ello" basta con llamar al m#todo Refres+Sc+ema de Command-uilder. *i desea conocer el comando generado autom4ticamente" puede obtener una referencia a los comandos generados autom4ticamente mediante los m#todos 6etInsertCommand" 6etUpdateCommand y 6etDeleteCommand del ob$eto Command-uilder. A continuacin" e&amine la propiedad Command1e't del Command asociado. En el e$emplo de cdigo siguiente se escribe en la consola el comando de actuali%acin generado autom4ticamente. 'opiar cdigo
Console.5rite6ine(#uilder.Ret:pdateCommand().Command,eCt)
En el siguiente e$emplo se contin8a con el cdigo del e$emplo anterior y se recrea la tabla Customers" en la que se sustituye la columna Company)ame por la columna Contact)ame. *e llama al m#todo Refres+Sc+ema para actuali%ar los comandos generados autom4ticamente con la informacin de esta nueva columna. '3 'opiar cdigo
// Assumes t!at connection is a valid SqlConnection o#Ject. connection.Open(); adapter.SelectCommand.Command,eCt = $SA6AC, Customer'D9 Contact1ame 0FO% d#o.Customers$; #uilder.Fe+res!Sc!ema(); custDS.,a#les.Femove(custDS.,a#les2$Customers$3); adapter.0ill(custDS9 $Customers$); // Code to modi+& t!e new ta#le in t!e DataSet !ere. // 5it!out t!e call to Fe+res!Sc!ema9 t!is line would +ail. adapter.:pdate(custDS9 $Customers$); connection.Close();
3ea tambi4n
// Assumes t!at connection is a valid SqlConnection o#Ject. SqlCommand ordersC%D = new SqlCommand( $SA6AC, Count(;) 0FO% Orders$9 connection); 'nt?) count = ('nt?))ordersC%D.ACecuteScalar();
3ea tambi4n /e'erencia
b'ommand escribe la clase DbCommand" as5 como todos sus miembros. OdbcCommand escribe la clase OdbcCommand" as5 como todos sus miembros. OleDbCommand escribe la clase OleDbCommand" as5 como todos sus miembros. OracleCommand escribe la clase OracleCommand" as5 como todos sus miembros. S%lCommand escribe la clase S%lCommand" as5 como todos sus miembros.
!dbc ataAdapter y el proveedor de datos de .NET Framework para !racle incluye un ob$eto !racle ataAdapter.
En esta seccin
El m#todo /ill del DataAdapter se usa para llenar un DataSet con los resultados de la propiedad SelectCommand del DataAdapter. El m#todo /ill acepta como argumentos un DataSet que se debe llenar y un ob$eto Data1able" o su nombre" que se debe llenar con las filas que devuelve SelectCommand. El m#todo /ill utili%a el ob$eto DataReader de forma impl5cita para devolver los nombres y tipos de columna utili%ados para crear las tablas de DataSet" as5 como los datos para llenar las filas de las tablas de DataSet. Las tablas y columnas slo se crean cuando no e&isten> en caso contrario" /ill utili%a el esquema e&istente de DataSet. Los tipos de columna se crean como tipos de .NET Framework conforme se indica en las tablas que aparecen en Asignar los tipos de datos del proveedor de datos de .NET para los tipos de datos de .NET Framework. No se crean claves principales a menos que e&istan en el origen de datos y se 6aya dado el valor (issingSc+emaAction Add#it+7ey a DataAdapter (issingSc+emaAction. *i el m#todo /ill determina que una tabla tiene clave principal" sobrescribe los datos del DataSet con los del origen de datos en aquellas filas en las que los valores de la columna de clave principal coincidan con los de la fila que devuelve el origen de datos. *i no se detecta ninguna clave principal" los datos se ane&an a las tablas del DataSet. /ill utili%a cualquier asignacin que pueda e&istir al llenar el DataSet 9vea 'onfigurar las asignaciones de ataTable y ata'olumn:.
Nota Si SelectCo!!and devuelve los resultados de una combinacin e'terna 5#7(E >#<N6, Data)dapter no establecer un valor $ri!ar*+e* para la tabla Data,able resultante. Es necesario definir $ri!ar*+e* para ase!urarse de que las filas duplicadas se resuelven correctamente. Para obtener ms informacin, vea %efinir una clave principal para una tabla. En el e$emplo de cdigo siguiente se crea una instancia de un *ql ataAdapter que utili%a un ob$eto *ql'onnection a la base de datos )ort+wind de -icrosoft *+L *erver y llena una ataTable en un DataSet con la lista de clientes. La instruccin *+L y los argumentos S%lConnection pasados al constructor S%lDataAdapter se utili%an para crear la propiedad *elect'ommand del S%lDataAdapter.
E$emplo
'3 'opiar cdigo
// Assumes t!at connection is a valid SqlConnection o#Ject. string quer&String = $SA6AC, Customer'D9 Compan&1ame 0FO% d#o.Customers$; SqlDataAdapter adapter = new SqlDataAdapter(quer&String9 connection); DataSet customers = new DataSet(); adapter.0ill(customers9 $Customers$);
Nota El cdi!o que aparece en este ejemplo no abre o cierra el objeto Connection de manera e'pl"cita. El mtodo Fill abre de forma impl"cita el objeto Connection que utiliza el Data)dapter cuando determina que esta cone'in no est abierta. ,uando el mtodo Fill 1a abierto la cone'in, el mismo mtodo la cierra cuando termina de utilizarla. Este 1ec1o simplifica el cdi!o cuando se trata de una operacin 9nica, como un mtodo Fill o 'pdate. Sin embar!o, en el caso de que se estn realizando varias operaciones que necesiten tener abierta una cone'in, puede mejorar el rendimiento de la aplicacin si llama e'pl"citamente al mtodo Open de Connection, realiza a continuacin las operaciones en el ori!en de datos y, finalmente, llama al mtodo Close de Connection. Es conveniente mantener abiertas las cone'iones del ori!en de datos lo ms brevemente posible con el fin de liberar recursos, de manera que estn disponibles para otras aplicaciones cliente.
cada origen de datos se pueden usar uno o varios ob$etos DataAdapter. Ejemplo En el e$emplo de cdigo siguiente se llena una lista de clientes a partir de la base de datos )ort+wind de -icrosoft *+L *erver ?/// y una lista de pedidos a partir de la base de datos )ort+wind almacenada en -icrosoft Access ?///. Las tablas de datos llenas se relacionan entre s5 mediante DataRelation" con lo que se puede mostrar una lista de clientes con los pedidos que 6a reali%ado cada uno. ,ara obtener m4s informacin sobre ob$etos DataRelation" vea Agregar una relacin entre tablas y E&plorar una relacin entre tablas. '3 'opiar cdigo
// Assumes t!at customerConnection is a valid SqlConnection o#Ject. // Assumes t!at orderConnection is a valid OleD#Connection o#Ject. SqlDataAdapter
custAdapter = new SqlDataAdapter( $SA6AC, ; 0FO% d#o.Customers$9 customerConnection); OleD#DataAdapter ordAdapter = new OleD#DataAdapter( $SA6AC, ; 0FO% Orders$9 orderConnection); DataSet customerOrders = new DataSet(); custAdapter.0ill(customerOrders9 $Customers$); ordAdapter.0ill(customerOrders9 $Orders$); DataFelation relation = customerOrders.Felations.Add($CustOrders$9 customerOrders.,a#les2$Customers$3.Columns2$Customer'D$39 customerOrders.,a#les2$Orders$3.Columns2$Customer'D$3); +oreac! (DataFow pFow in customerOrders.,a#les2$Customers$3.Fows) { Console.5rite6ine(pFow2$Customer'D$3); +oreac! (DataFow cFow in pFow.RetC!ildFows(relation)) Console.5rite6ine($<t$ K cFow2$Order'D$3); "
Tipo decimal de SQ Ser!er
DataSet almacena de forma predeterminada los datos utili%ando tipos de datos de .NET Framework. En la mayor parte de las aplicaciones" estos tipos proporcionan una representacin adecuada de la informacin del origen de datos. *in embargo" esa representacin puede ocasionar problemas cuando el tipo de datos del origen de datos es decimal o num#rico de *+L *erver. El tipo de datos decimal de .NET Framework permite un m4&imo de ?P d5gitos significativos" mientras que el tipo decimal de *+L *erver permite @P d5gitos. 'uando S%lDataAdapter determina" durante una operacin /ill" que la precisin de un campo decimal de *+L *erver es mayor de ?P caracteres" la fila actual no se agrega a Data1able. En cambio" se produce un evento /ill&rror que le permite decidir si se debe producir o no una p#rdida de precisin y tomar las medidas adecuadas. ,ara obtener m4s informacin sobre el evento /ill&rror" vea Traba$ar con eventos ataAdapter. ,ara obtener el valor decimal de *+L *erver tambi#n" puede utili%ar un ob$eto *ql ata1eader y llamar al m#todo Net*ql ecimal. A !.NET ?./ incorpora compatibilidad me$orada para *ystem. ata.*qlTypes en el DataSet. ,ara obtener m4s informacin" vea *qlTypes y el ata*et.
Captulos de O E D"
*e pueden usar con$untos $er4rquicos de filas" o cap5tulos 9tipo D-18P&9:C:AP1&R de !LE tipo adC+apter de A !:" para llenar un DataSet. 'uando !le b ataAdapter encuentra una columna que tiene un cap5tulo" durante una operacin /ill" se crea una Data1able para ella y la tabla se llena con las columnas y filas del cap5tulo. La tabla creada para la columna con cap5tulo recibe como nombre el de la tabla primaria y el de la columna con cap5tulo. El nombre tiene el formato GnombreDeTablaPrimariaNombreDeColumnaConCaptuloG. *i ya e&iste en el DataSet una tabla que tenga el nombre de la columna con cap5tulo" esa tabla se llena con los datos del cap5tulo. *i ninguna de las columnas de la tabla e&istente coincide con una de las columnas del cap5tulo" se agrega una nueva columna a la tabla. Antes de que se llenen las tablas del DataSet con los datos de las columnas con cap5tulos" se crea una relacin entre las tablas primaria y secundaria del con$unto $er4rquico de filas> para ello" se agrega una columna de tipo entero a las tablas primaria y secundaria" se establece la propiedad de incremento autom4tico en la columna de la tabla primaria y se crea una DataRelation entre las columnas agregadas de ambas tablas. ,ara dar nombre a la relacin" se utili%an los nombres )y
de la tabla primaria y de la columna con cap5tulo con el formato GnombreDeTablaPrimariaNombreDeColumnaConCaptuloG. Tenga en cuenta que la columna relacionada slo e&iste en el DataSet. !tras operaciones de llenado que se realicen a continuacin desde el origen de datos ir4n agregando nuevas filas a las tablas en lugar de introducir cambios en las filas ya e&istentes. Tenga en cuenta adem4s que" si se utili%a una sobrecarga de DataAdapter /ill que acepte una tabla Data1able" #sa ser4 la 8nica tabla que se llene. En este caso tambi#n se agrega a la tabla una columna de tipo entero y con incremento autom4tico" aunque no se crea ni rellena ninguna tabla secundaria" ni se crea ninguna relacin. En el e$emplo siguiente se utili%a el proveedor -* ata*6ape para generar un cap5tulo con la columna de pedidos reali%ados por cada uno de los clientes de una lista. A continuacin se llena con esos datos un DataSet. '3 'opiar cdigo
using (OleD#Connection connection = new OleD#Connection($*rovider=%SDataS!ape;Data *rovider=S76O6ADB;$ K $Data Source=(local);'ntegrated Securit&=SS*';'nitial Catalog=nort!wind$)) { OleD#DataAdapter adapter = new OleD#DataAdapter($SEA*A {SA6AC, Customer'D9 Compan&1ame 0FO% Customers" $ K $A**A1D ({SA6AC, Customer'D9 Order'D 0FO% Orders" AS Orders $ K $FA6A,A Customer'D ,O Customer'D)$9 connection); DataSet customers = new DataSet(); adapter.0ill(customers9 $Customers$); "
=na ve% finali%ada la operacin /ill" el DataSet contiene dos tablas( Customers y CustomersOrders" donde CustomersOrders representa la columna con cap5tulo. *e agrega una columna adicional con el nombre Orders a la tabla Customers y una columna adicional con el nombre CustomersOrders a la tabla CustomersOrders. La columna Orders en la tabla Customers se establece con incremento autom4tico. *e crea tambi#n una relacin DataRelation" CustomersOrders" utili%ando las columnas que se 6an agregado a las tablas donde la tabla Customers es la primaria. Las siguientes tablas muestran algunos e$emplos de los resultados. 1able)ame2 Customers Custo!erID :$)?< :N:( Co!pan*Na!e :lfreds )utter+iste :na (rujillo Emparedados y 1elados Orders . -
1able)ame2 CustomersOrders Custo!erID :$)?< :$)?< :N:( :N:( OrderID -.@AB -.@CD -.B.E -.@DF Custo!ersOrders . . -
3ea tambi4n
adapter.*arameters.Add( - $PCompan&1ame$9 SqlD#,&pe.1C!ar9 (L9 $Compan&1ame$) Dim parameter As Sql*arameter = adapter.:pdateCommand.*arameters.Add($PCustomer'D$9 - SqlD#,&pe.1C!ar9 L9 $Customer'D$) parameter.SourceQersion = DataFowQersion.Original
El m#todo Add de la coleccin Parameters toma de Data1able el nombre del par4metro" el tipo espec5fico de DataAdapter" el tama7o 9si corresponde al tipo: y el nombre de SourceColumn. !bserve que el valor de Source5ersion del par4metro @CustomerID est4 establecido a Original. e esta forma se garanti%a que la fila e&istente en el origen de datos se actuali%a cuando el valor de la columna o columnas identificadas 6a cambiado en la fila DataRow modificada. En ese caso" el valor de la fila Original coincidir5a con el valor actual en el origen de datos y el valor de la fila
Current contendr5a el valor actuali%ado. No se asigna ning8n valor a Source5ersion para el par4metro @CompanyName por lo que se usa el predeterminado" el de la fila Current.
E$emplo de S+lClient
En el e$emplo siguiente se muestran instrucciones *+L de e$emplo que se pueden utili%ar como Command1e't para las propiedades SelectCommand" InsertCommand" UpdateCommand y DeleteCommand del S%lDataAdapter. En el ob$eto S%lDataAdapter debe usar par4metros con nombre. '3 'opiar cdigo
string selectS76 = $SA6AC, Customer'D9 Compan&1ame 0FO% Customers 5EAFA Countr&Fegion = $ K $PCountr&Fegion A1D Cit& = PCit&$; string insertS76 = $'1SAF, '1,O Customers (Customer'D9 Compan&1ame) $ K $QA6:AS (PCustomer'D9 PCompan&1ame)$; string updateS76 = $:*DA,A Customers SA, Customer'D = PCustomer'D9 $ K $Compan&1ame = PCompan&1ame 5EAFA Customer'D = POldCustomer'D$; string deleteS76 = $DA6A,A 0FO% Customers 5EAFA Customer'D = PCustomer'D$;
E$emplo de OleDb u Odbc
En el caso de los ob$etos !le b ataAdapter y !dbc ataAdapter" debe utili%ar signos de interrogacin de cierre 9L: como marcadores de posicin para identificar los par4metros. '3 'opiar cdigo
string selectS76 = $SA6AC, Customer'D9 Compan&1ame 0FO% Customers $ K $5EAFA Countr&Fegion = T A1D Cit& = T$; string insertS76 = $'1SAF, '1,O Customers (Customer'D9 Compan&1ame) $ K $QA6:AS (T9 T)$; string updateS76 = $:*DA,A Customers SA, Customer'D = T9 Compan&1ame = T $ K $5EAFA Customer'D = T $; string deleteS76 = $DA6A,A 0FO% Customers 5EAFA Customer'D = T$;
Las instrucciones de consulta con par4metros definen qu# par4metros de entrada y de salida se deben crear. ,ara crear un par4metro" se utili%a el m#todo Parameters Add o el constructor Parameter con el fin de especificar el nombre de columna" tipo de datos y tama7o. En el caso de tipos de datos intr5nsecos" como Integer" no es necesario incluir el tama7o" aunque puede especificar el tama7o predeterminado. En el e$emplo de cdigo siguiente se crean los par4metros para la instruccin *+L del e$emplo anterior y se llena un DataSet.
S+lClient
'3 'opiar cdigo
// Assumes t!at connection is a valid SqlConnection o#Ject. SqlDataAdapter adapter = new SqlDataAdapter(); SqlCommand selectC%D = new
SqlCommand(selectS769 connection); adapter.SelectCommand = selectC%D; // Add parameters and set values. selectC%D.*arameters.Add( $PCountr&Fegion$9 SqlD#,&pe.1QarC!ar9 (L).Qalue = $:U$; selectC%D.*arameters.Add( $PCit&$9 SqlD#,&pe.1QarC!ar9 (L).Qalue = $6ondon$; DataSet customers = new DataSet(); adapter.0ill(customers9 $Customers$);
OleDb
// Assumes t!at connection is a valid OleD#Connection o#Ject. OleD#DataAdapter adapter = new OleD#DataAdapter(); OleD#Command selectC%D = new OleD#Command(selectS769 connection); adapter.SelectCommand = selectC%D; // Add parameters and set values. selectC%D.*arameters.Add( $PCountr&Fegion$9 OleD#,&pe.QarC!ar9 (L).Qalue = $:U$; selectC%D.*arameters.Add( $PCit&$9 OleD#,&pe.QarC!ar9 (L).Qalue = $6ondon$; DataSet customers = new DataSet(); adapter.0ill(customers9 $Customers$);
Odbc
'3 'opiar cdigo
// Assumes t!at connection is a valid Od#cConnection o#Ject. Od#cDataAdapter adapter = new Od#cDataAdapter(); Od#cCommand selectC%D = new Od#cCommand(selectS769 connection); adapter.SelectCommand = selectC%D; //Add *arameters and set values. selectC%D.*arameters.Add($PCountr&Fegion$9 Od#c,&pe.QarC!ar9 (L).Qalue = $:U$; selectC%D.*arameters.Add($PCit&$9 Od#c,&pe.QarC!ar9 (L).Qalue = $6ondon$; DataSet customers = new DataSet(); adapter.0ill(customers9 $Customers$);
Nota Si no se proporciona un nombre para un parmetro, ste toma un nombre predeterminado y secuencial del tipo Parameter N, que comienza por =Parameter-=. Se recomienda evitar la convencin de nomenclatura del tipo =Parameter N= al asi!nar un nombre de parmetro, ya que dic1o nombre podr"a entrar en conflicto con un nombre de parmetro predeterminado e'istente en la $ara!eterCollection. Si el nombre proporcionado ya e'iste, se inicia una e'cepcin.
%arameter.DbType
El tipo de un Parameter es espec5fico del proveedor de datos de .NET Framework. Al especificar el tipo" el valor de Parameter se convierte al tipo del proveedor de datos de .NET Framework antes de pasarlo al origen de datos. Tambi#n se puede especificar el tipo de un Parameter de forma gen#rica si se establece la propiedad Db1ype del ob$eto Parameter en un determinado bType.
El tipo del proveedor de datos de .NET Framework del ob$eto Parameter se deduce del tipo de .NET Framework del valor 5alue del ob$eto Parameter o a partir del Db1ype del ob$eto Parameter. En la siguiente tabla se muestra el tipo Parameter inferido en funcin del ob$eto que se 6a pasado como valor Parameter o del Db1ype especificado. ,ipo de .NE, Fra!e(or- S*ste!.Data.Db,*pe bool b*te b*te01 /oolean /*te /inar*
2ar/inar*. Esta 2ar/inar* conversin impl"cita producir un error si la matriz de bytes es mayor que el tamaHo m'imo de una 2ar/inar*, que es E... bytes. En los casos de las matrices de bytes mayores de E... bytes, establezca S.lDb,*pe e'pl"citamente. No es posible deducir el valor de S.lDb,*pe a partir de c ar. C ar
c ar
C ar
/*te
string
String
N2arC ar. Esta 2ar9C ar conversin impl"cita !enera un error en el caso de que la cadena sea mayor que el tamaHo m'imo de una N2arC ar, que es A.... caracteres.. En el caso de cadenas mayores de A.... caracteres, el valor de S.lDb,*pe se debe establecer de forma e'pl"cita. No es posible deducir el valor de S.lDb,*pe a partir de ,i!eSpan. No es posible deducir el valor de S.lDb,*pe a D/,i!e
,i!eSpan
,i!e
,i!e
Date,i!e
'Int34
'Int34
'nsignedS!allInt Int
'Int34
partir de 'Int34. 'Int56 'Int56 No es posible deducir el valor de S.lDb,*pe a partir de 'Int56. No es posible deducir el valor de S.lDb,*pe a partir de 'Int47. 2arC ar C ar Mone* 'nsignedInt /igInt 'Int56
'Int47
'Int47
'nsigned/igInt
Nu!eric
Nu!ber
2arC ar C ar Currenc*
2arC ar C ar
2arC ar C ar
Date
No es posible deducir el D/Date valor de S.l,*pe a partir de Date. No es posible deducir el ,in*Int valor de S.l,*pe a partir de S/*te. NC ar 9C ar
S/*te
StringFi#ed"engt ,i!e
No es posible deducir el D/,i!e valor de S.l,*pe a partir de ,i!e. No es posible deducir el valor de S.lDb,*pe a partir de 2arNu!eric. 2arNu!eric
2arNu!eric
Nota $os proveedores de datos de .NE( )rame*or+ que se incluyen con la versin -.. de .NE( )rame*or+ no verifican la precisin ni la escala de los valores de parmetros de tipo Deci!al, lo que puede provocar que se inserten datos truncados en el ori!en de datos. Si est utilizando la versin -.. de .NE( )rame*or+, valide los valores de precisin y escala de los valores de tipo Deci!al antes de establecer el valor de parmetro. En el caso de la versin -.- y versiones posteriores de .NE( )rame*or+, al confi!urar un valor de parmetro Deci!al con un valor de precisin que no es vlido, se inicia una e'cepcin. $os valores de escala que sobrepasan la escala del parmetro Deci!al si!uen truncados. Nota En el caso de la versin -.. de .NE( )rame*or+, puede utilizar System.%ata.Sql(ypes cuando trabaje con System.%ata.Sql,lient. Para obtener ms informacin, vea (rabajo con Sql(ypes.
%arameter.Direction
En la tabla siguiente se muestran los valores que se pueden utili%ar con la enumeracin ,arameter irection para establecer la Direction del Parameter. No!bre del !ie!bro Entrada InputOutput Resultados Descripcin Se trata de un parmetro de entrada. Iste es el valor predeterminado. El parmetro puede ser de entrada o de salida. Se trata de un parmetro de salida.
2alor devuelto
En el e$emplo de cdigo siguiente se muestra cmo establecer el valor Direction de Parameter. 'opiar cdigo
parameter.Direction = *arameterDirection.Output
%arameter.SourceColumn6 %arameter.Source3ersion
SourceColumn y Source5ersion se pueden pasar como argumentos al constructor Parameter o tambi#n se pueden establecer como propiedades de un Parameter e&istente. SourceColumn es el nombre de la valor. En la tabla siguiente se muestran los valores de la enumeracin su uso con Source5ersion. No!bre del !ie!bro Current Default Original $roposed Descripcin El parmetro utiliza el valor actual de la columna. Iste es el valor predeterminado. El parmetro utiliza el valor Default2alue de la columna. El parmetro utiliza el valor ori!inal de la columna. El parmetro utiliza un valor propuesto. ata1ow2ersion disponibles para ata'olumn de la ata1ow en la que se recupera el valor del Parameter. Source5ersion especifica qu# versin de DataRow debe usar DataAdapter para recuperar el
En el siguiente e$emplo de cdigo se define una instruccin =, ATE en la que la columna CustomerID se utili%a como SourceColumn para dos par4metros( @CustomerID 9SA,
Customer'D = PCustomer'D: y @ ldCustomerID 95EAFA Customer'D = POldCustomer'D:. El par4metro @CustomerID se utili%a para actuali%ar la columna
CustomerID de forma que tenga el valor actual de DataRow. En consecuencia" se usa CustomerID SourceColumn con el valor Current para Source5ersion. El par4metro @ ldCustomerID se utili%a para identificar la fila actual en el origen de datos. ado que el valor de la columna que coincide con @ ldCustomerID se encuentra en la versin Original de la fila" tambi#n se usa el mismo SourceColumn 9CustomerID: con el valor Original para Source5ersion.
S+lClient
'3 'opiar cdigo
adapter.:pdateCommand.*arameters.Add( $PCustomer'D$9 SqlD#,&pe.1C!ar9 L9 $Customer'D$); adapter.:pdateCommand.*arameters.Add( $PCompan&1ame$9 SqlD#,&pe.1QarC!ar9 >=9 $Compan&1ame$); Sql*arameter parameter = adapter.:pdateCommand.*arameters.Add( $POldCustomer'D$9 SqlD#,&pe.1C!ar9 L9 $Customer'D$); parameter.SourceQersion = DataFowQersion.Original;
(pdated/o*Source
,uede controlar la forma en que los valores devueltos desde el origen de datos se asignan al DataSet. ,ara ello" puede usar la propiedad UpdatedRowSource del ob$eto Command. Al asignar la propiedad UpdatedRowSource a uno de los valores de enumeracin =pdate1ow*ource" puede determinar si los par4metros que devuelve el comando DataAdapter se deben omitir o aplicar a la fila cambiada en el DataSet. Tambi#n puede especificar si la primera fila devuelta 9si e&iste: se aplica a la fila modificada en el DataSet. En la tabla siguiente se describen los distintos valores de la enumeracin UpdateRowSource y la forma en que afectan al comportamiento del comando usado con DataAdapter. 'pdateRo(Source /ot Descripcin (anto los parmetros de salida como la primera fila del conjunto de resultados devuelto se pueden asi!nar a la fila modificada en DataSet.
FirstReturnedRecord Slo los datos de la primera fila del conjunto de resultados devuelto se pueden asi!nar a la fila modificada en el DataSet. Ninguna Output$ara!eters Se pasan por alto todos los parmetros de salida y las filas del conjunto de resultados devuelto. Slo los parmetros de salida se pueden asi!nar a la fila modificada del DataSet.
3ea tambi4n
Evento
Descripcin
Ro('pdating Est a punto de comenzar una operacin 7P%:(E, <NSE ( o %E$E(E en una fila 5mediante una llamada a uno de los mtodos 'pdate6. Ro('pdated Se 1a completado una operacin 7P%:(E, <NSE ( o %E$E(E en una fila 5mediante una llamada a uno de los mtodos 'pdate6. FillError Se 1a producido un error durante una operacin Fill.
/o*(pdating y /o*(pdated
El evento RowUpdating se activa antes de que se produ%ca la actuali%acin de una fila del ata*et en el origen de datos. El evento RowUpdated se activa despu#s de producirse la actuali%acin de una fila del DataSet en el origen de datos. ,or lo tanto" puede utili%ar RowUpdating para modificar el comportamiento de la actuali%acin antes de que tenga lugar" proporcionar un control adicional del proceso durante la actuali%acin" conservar una referencia a la fila actuali%ada" cancelar la actuali%acin actual y programarla como parte de un proceso por lotes que se e$ecutar4 despu#s" entre otras acciones. RowUpdated es 8til para reaccionar cuando se producen errores y e&cepciones durante la actuali%acin. ,uede agregar informacin de errores al DataSet" as5 como procedimientos de reintento" etc#tera. Los argumentos 1ow=pdatingEventArgs y 1ow=pdatedEventArgs pasados a los eventos RowUpdating y RowUpdated incluyen( una propiedad Command que 6ace referencia al ob$eto Command que se est4 utili%ando para reali%ar la actuali%acin> una propiedad Row que 6ace
referencia al ob$eto DataRow que contiene la informacin actuali%ada> una propiedad Statement1ype para el tipo de actuali%acin que se est4 llevando a cabo> la 1able(apping" si es pertinente y el Status de la operacin. ,uede utili%ar la propiedad Status para determinar si se 6a producido o no un error durante la operacin y" si as5 se desea" controlar las acciones que se emprenden con las filas actuales y las resultantes de la operacin. 'uando se produce el evento" la propiedad Status toma el valor Continue o &rrorsOccurred. En la tabla siguiente se muestran los valores que se pueden asignar a la propiedad Status para controlar las acciones siguientes en el proceso de actuali%acin.
Descripcin ,ontinuar la operacin de actualizacin. :nular la operacin de actualizacin e iniciar una e'cepcin. #mitir la fila actual y continuar la operacin de actualizacin. :nular la operacin de actualizacin sin iniciar una e'cepcin.
Al asignar a la propiedad Status al valor &rrorsOccurred se inicia una e&cepcin. ,uede controlar qu# e&cepciones se inician si establece el valor correspondiente a la e&cepcin deseada en la propiedad &rrors. El uso de un valor distinto para la propiedad Status evita que se inicie una e&cepcin. Tambi#n puede utili%ar la propiedad ContinueUpdateOn&rror para controlar los errores producidos por las filas actuali%adas. 'uando DataAdapter ContinueUpdateOn&rror tiene el valor true y la actuali%acin de una fila inicia una e&cepcin" el te&to de la e&cepcin se coloca en la informacinRow&rror de la fila en cuestin y el proceso contin8a sin que se inicie una e&cepcin. detectan. En el e$emplo de cdigo siguiente se muestra cmo se pueden agregar y quitar controladores de eventos. El controlador de eventos RowUpdating mantiene un registro con todos los registros eliminados y una marca de tiempo asociada a cada uno de ellos. El controlador de eventos RowUpdated agrega informacin de error a la propiedad Row&rror de la fila correspondiente en el DataSet" evita que se inicie la e&cepcin y de$a continuar el proceso 9al igual que ContinueUpdateOn&rror I true:. '3 'opiar cdigo e esta forma" puede reaccionar frente a errores cuando finalice el proceso Update" a diferencia del evento RowUpdated" que permite reaccionar frente a los errores cuando se
// Assumes t!at connection is a valid SqlConnection o#Ject. SqlDataAdapter custAdapter = new SqlDataAdapter( $SA6AC, Customer'D9 Compan&1ame 0FO% Customers$9 connection); // Add !andlers. custAdapter.Fow:pdating K= new SqlFow:pdatingAventEandler(OnFow:pdating); custAdapter.Fow:pdated K= new SqlFow:pdatedAventEandler(OnFow:pdated); // Set DataAdapter command properties9 +ill DataSet9 modi+& DataSet. custAdapter.:pdate(custDS9 $Customers$); // Femove !andlers. custAdapter.Fow:pdating O= new SqlFow:pdatingAventEandler(OnFow:pdating); custAdapter.Fow:pdated O= new SqlFow:pdatedAventEandler(OnFow:pdated); protected static void OnFow:pdating( o#Ject sender9 SqlFow:pdatingAventArgs args) { i+
(args.Statement,&pe == Statement,&pe.Delete) { S&stem.'O.,eCt5riter tw = S&stem.'O.0ile.Append,eCt($Deletes.log$); tw.5rite6ine( ${="8 Customer {(" Deleted.$9 Date,ime.1ow9 args.Fow2$Customer'D$9 DataFowQersion.Original3); tw.Close(); " " protected static void OnFow:pdated( o#Ject sender9 SqlFow:pdatedAventArgs args) { i+ (args.Status == :pdateStatus.ArrorsOccurred) { args.Fow.FowArror = args.Arrors.%essage; args.Status = :pdateStatus.S ipCurrentFow; " "
-illError
DataAdapter emite el evento /ill&rror cuando se produce un error durante una operacin de llenado 9/ill:. Este tipo de error suele producirse si al convertir los datos de la fila que se agrega a un tipo de .NET Framework se produce una p#rdida de precisin. *i el error se produce durante una operacin /ill" la fila actual no se agrega a Data1able. El evento /ill&rror permite resolver el error y agregar la fila" o pasar por alto la fila e&cluida y continuar con la operacin /ill. El ob$eto /ill&rror&ventArgs que se pasa al evento /ill&rror puede contener varias propiedades que permiten reaccionar en caso de errores y resolverlos. En la tabla siguiente se muestran las propiedades del ob$eto /ill&rror&ventArgs.
Data,abl #bjeto Data,able que se estaba llenando cuando ocurri el error. e 2alores 0atriz de objetos que contiene los valores de la fila que se est a!re!ando cuando se produce el error. $as referencias de orden de la matriz 2alues coinciden con las de las columnas de la fila que se estaba a!re!ando. Por ejemplo, 2alues0:1 es el valor que se a!re!a en la primera columna de la fila. Permite ele!ir si desea iniciar una e'cepcin o no. Si asi!na a la propiedad Continue el valor false, la operacin Fill en curso se detiene y se inicia una e'cepcin. Si a la propiedad Continue se le asi!na el valor true, la operacin Fill contin9a pese al error.
Continue
En el e$emplo de cdigo siguiente se agrega un controlador de eventos para el evento /ill&rror de DataAdapter. En el cdigo del evento /ill&rror" el e$emplo determina si 6ay una posible p#rdida de precisin y ofrece la posibilidad de reaccionar en ese caso. '3 'opiar cdigo
adapter.0illArror K= new 0illArrorAventEandler(0illArror); DataSet dataSet = new DataSet(); adapter.0ill(dataSet9 $,!is,a#le$); protected static void 0illArror(o#Ject sender9 0illArrorAventArgs args) { i+ (args.Arrors.Ret,&pe() == t&peo+(S&stem.Over+lowACception)) { // Code to !andle precision loss. //Add a row to ta#le using t!e values +rom t!e +irst two columns. DataFow m&Fow = args.Data,a#le.Fows.Add(new o#Ject23 {args.Qalues2=39 args.Qalues2(39 DB1ull.Qalue"); //Set t!e FowArror containing t!e value +or t!e t!ird column. args.FowArror = $Over+lowACception Ancountered. Qalue +rom data source8 $ K args.Qalues2)3; args.Continue = true; " "
3ea tambi4n
Nota Si una columna del ori!en de datos es de incremento automtico, el mtodo FillSc e!a o el mtodo Fill con el valor )dd9it +e* en la propiedad MissingSc e!a)ction crean una DataColu!n con el valor de la propiedad )utoIncre!ent establecido como true. Sin embar!o, en este caso debe definir manualmente los valores de )utoIncre!entStep y )utoIncre!entSeed. Para obtener ms informacin sobre las columnas de incremento automtico, vea ,rear columnas :uto<ncrement. Al utili%ar /illSc+ema o establecer el valor Add#it+7ey en (issingSc+emaAction" se precisa un proceso adicional en el origen de datos para determinar la informacin de la columna de clave principal. Este proceso adicional puede reducir el rendimiento. *i conoce en la fase de dise7o la informacin de la clave principal" es aconse$able especificar de modo e&pl5cito la columna o columnas que la forman para me$orar el rendimiento. ,ara obtener m4s informacin sobre la especificacin de modo e&pl5cito de informacin de la clave principal de una tabla" vea clave principal para una tabla. En el e$emplo de cdigo siguiente se muestra cmo agregar la informacin del esquema a un DataSet mediante /illSc+ema. '3 'opiar cdigo efinir una
Nota Si se llama al mtodo FillSc e!a del objeto OleDbData)dapter para un comando que devuelve m9ltiples conjuntos de resultados, slo se devuelve la informacin del esquema del primer conjunto de resultados. :l devolver la informacin del esquema de m9ltiples conjuntos de resultados mediante OleDbData)dapter, es aconsejable asi!nar a la propiedad MissingSc e!a)ction el valor )dd9it +e* y obtener la informacin del esquema al llamar al mtodo Fill.
3ea tambi4n
E$emplo
En el e$emplo se utili%a el siguiente procedimiento almacenado para insertar una categor5a nueva en la tabla )ort+wind Categories" que toma el valor de la columna Category)ame como par4metro de entrada y utili%a la funcin *'!,EQ; ENT;TJ9: para recuperar el nuevo valor del campo de identidad CategoryID y devolverlo en un par4metro de salida. La instruccin 1ET=1N utili%a la funcin RR1!<'!=NT para devolver el n8mero de filas insertadas. 'opiar cdigo
CFAA,A *FOCAD:FA 'nsertCategor& PCategor&1ame nc!ar((L)9 P'dentit& int O:,*:, AS SA, 1OCO:1, O1 '1SAF, '1,O Categories (Categor&1ame) QA6:AS(PCategor&1ame) SA, P'dentit& = SCO*A-'DA1,',G() FA,:F1 PPFO5CO:1,
En el siguiente e$emplo se utili%a el anterior procedimiento almacenado InsertCategory como origen de la propiedad ;nsert'ommand de *ql ataAdapter. El par4metro de salida ;Identity y el valor devuelto se refle$ar4n en ata*et una ve% que se 6aya insertado el registro en la base de dados al llamar al m#todo Update del S%lDataAdapter.
Nota En el caso de #le%b%ata:dapter, los parmetros con un Parameter%irection con el valor Return2alue se deben especificar antes que los restantes parmetros. '3 'opiar cdigo
// Assumes t!at connection represents a SqlConnection o#Ject. SqlDataAdapter adapter = new SqlDataAdapter( $SA6AC, Categor&'D9 Categor&1ame 0FO% d#o.Categories$9 connection); adapter.'nsertCommand = new SqlCommand($'nsertCategor&$9 connection); adapter.'nsertCommand.Command,&pe = Command,&pe.Stored*rocedure; Sql*arameter parameter = adapter.'nsertCommand.*arameters.Add( $PFowCount$9 SqlD#,&pe.'nt); parameter.Direction = *arameterDirection.FeturnQalue; adapter.'nsertCommand.*arameters.Add( $PCategor&1ame$9 SqlD#,&pe.1C!ar9 (L9 $Categor&1ame$); parameter = adapter.'nsertCommand.*arameters.Add( $P'dentit&$9 SqlD#,&pe.'nt9 =9 $Categor&'D$); parameter.Direction = *arameterDirection.Output; DataSet categoriesDS = new DataSet(); adapter.0ill(categoriesDS9 $Categories$); DataFow newFow = categoriesDS.,a#les2$Categories$3.1ewFow(); newFow2$Categor&1ame$3 = $1ew Categor&$; categoriesDS.,a#les2$Categories$3.Fows.Add(newFow); adapter.:pdate(categoriesDS9 $Categories$); 'nt?) rowCount = ('nt?))adapter.'nsertCommand.*arameters2$PFowCount$3.Qalue;
CFAA,A *FOCAD:FA 'nsertCategor& PCategor&1ame nc!ar((L)9 P'dentit& int O:, AS '1SAF, '1,O Categories (Categor&1ame) QA6:AS(PCategor&1ame) SA, P'dentit& = SCO*A-'DA1,',G()
A continuacin" el procedimiento almacenado InsertCategory se puede especificar como el origen del ;nsert'ommand. *e crea un par4metro para recibir el par4metro de salida de identidad. Ese par4metro tiene un valor ,arameter irection de !utput y tiene una SourceColumn especificada como columna CategoryID de la tabla local Categories en el DataSet. 'uando se procesa InsertCommand para una fila agregada" se devuelve el valor de identidad de incremento autom4tico como este par4metro de salida y se coloca en la columna CategoryID de la fila actual. En el siguiente e$emplo de cdigo se muestra cmo devolver el valor de incremento autom4tico como el par4metro de salida y cmo especificarlo como el valor de origen para la columna CategoryID del DataSet. '3 'opiar cdigo
// Assumes t!at connection is a valid SqlConnection o#Ject. SqlDataAdapter adapter = new SqlDataAdapter( $SA6AC, Categor&'D9 Categor&1ame 0FO% d#o.Categories$9 connection); adapter.'nsertCommand = new SqlCommand($'nsertCategor&$9 connection); adapter.'nsertCommand.Command,&pe = Command,&pe.Stored*rocedure; adapter.'nsertCommand.*arameters.Add( $PCategor&1ame$9 SqlD#,&pe.1C!ar9 (L9 $Categor&1ame$); Sql*arameter parameter = adapter.'nsertCommand.*arameters.Add( $P'dentit&$9 SqlD#,&pe.'nt9 =9 $Categor&'D$); parameter.Direction = *arameterDirection.Output; connection.Open(); DataSet categories = new DataSet(); adapter.0ill(categories9 $Categories$); DataFow newFow = categories.,a#les2$Categories$3.1ewFow(); newFow2$Categor&1ame$3 = $1ew Categor&$; categories.,a#les2$Categories$3.Fows.Add(newFow); adapter.:pdate(categories9 $Categories$); connection.Close();
/ecuperar !alores de autonumeracin de ,icroso't Access
-icrosoft Access no admite procedimientos almacenados ni el procesamiento de comandos por lotes" por lo que no es posible asignar un par4metro de salida a la columna de origen de la tabla en el e$emplo anterior. *in embargo" -icrosoft Access ?/// o posterior admite la propiedad ;;ID&)1I18 para recuperar el valor de un campo Autonum#rico despu#s de una insercin 9con
;N*E1T:. -ediante el evento RowUpdated es posible determinar si se 6a producido una insercin" recuperar el 8ltimo valor de autonumeracin y ponerlo en la columna de identidad de la tabla local del DataSet. En el siguiente e$emplo de cdigo se muestra cmo insertar un nuevo valor en la tabla 'ategories de la base de datos )ort+wind de -icrosoft Access ?/// mediante un !le b ataAdapter. En el e$emplo se utili%a el evento RowUpdated para rellenar los valores de autonumeracin generados por el motor Fet y la base de datos de Access al insertar un registro en la tabla Categories. Hay que tener en cuenta que esto slo funcionar4 con el proveedor !LE Access ?/// o posterior. ) de Fet C./ y -icrosoft
// Assumes t!at connection is a valid OleD#Connection o#Ject. OleD#DataAdapter adapter = new OleD#DataAdapter( $SA6AC, Categor&'D9 Categor&1ame 0FO% Categories OFDAF BG Categor&'D$9 connection); adapter.'nsertCommand = new OleD#Command( $'1SAF, '1,O Categories (Categor&1ame) Qalues(T)$9 connection); adapter.'nsertCommand.Command,&pe = Command,&pe.,eCt; adapter.'nsertCommand.*arameters.Add( - $PCategor&1ame$9 OleD#,&pe.C!ar9 (L9 $Categor&1ame$); connection.Open(); // 0ill t!e DataSet. DataSet categories = new DataSet(); adapter.0ill(categories9 $Categories$); // Add a new row. DataFow newFow = categories.,a#les2$Categories$3.1ewFow(); newFow2$Categor&1ame$3 = $1ew Categor&$; categories.,a#les2$Categories$3.Fows.Add(newFow); // 'nclude an event to +ill in t!e Autonum#er value. adapter.Fow:pdated K= new OleD#Fow:pdatedAventEandler(OnFow:pdated); // :pdate t!e DataSet. adapter.:pdate(categories9 $Categories$); connection.Close(); // Avent procedure +or OnFow:pdated protected static void OnFow:pdated( o#Ject sender9 OleD#Fow:pdatedAventArgs args) { // 'nclude a varia#le and a command to retrieve t!e identit& value +rom t!e Access data#ase. int new'D = =; OleD#Command idC%D = new OleD#Command( $SA6AC, PP'DA1,',G$9 connection); i+ (args.Statement,&pe == Statement,&pe.'nsert) { // Fetrieve t!e identit& value and store it in t!e Categor&'D column. new'D = (int)idC%D.ACecuteScalar(); args.Fow2$Categor&'D$3 = new'D; " "
3ea tambi4n
Data,a#le%apping mapping = adapter.,a#le%appings.Add($,a#le$9 $1ort!windCustomers$); mapping.Column%appings.Add($Compan&1ame$9 $Compan&$); mapping.Column%appings.Add($Contact1ame$9 $Contact$); mapping.Column%appings.Add($*ostalCode$9 $V'*Code$); adapter.0ill(custDS);
En situaciones m4s avan%adas" puede que desee que el mismo DataAdapter permita la carga de distintas tablas" cada una con sus propias asignaciones. ,ara ello" basta con agregar m4s ob$etos Data1able(apping. 'uando al m#todo /ill se le pasa una instancia de un DataSet y un nombre de Data1able(apping" se utili%a la asignacin de ese nombre" si e&iste" o un Data1able con ese nombre" en caso contrario. En los e$emplos siguientes se crea un Data1able(apping denominado Customers y una Data1able denominada -i01al$Sc+ema. En el e$emplo se asignan a continuacin las filas devueltas por la instruccin *ELE'T a la Data1able -i01al$Sc+ema. '3 'opiar cdigo
',a#le%apping mapping = adapter.,a#le%appings.Add($Customers$9 $BiW,al Sc!ema$); mapping.Column%appings.Add($Customer'D$9 $Client'D$); mapping.Column%appings.Add($Compan&1ame$9 $Client1ame$); mapping.Column%appings.Add($Contact1ame$9 $Contact$); mapping.Column%appings.Add($*ostalCode$9 $V'*$); adapter.0ill(custDS9 $Customers$);
Nota
Si no se proporciona un nombre de columna de ori!en en una asi!nacin de columnas o no se identifica un nombre de tabla de ori!en en una asi!nacin de tablas, se !eneran nombres predeterminados de forma automtica. Si no se proporciona una columna de ori!en en una asi!nacin de columnas, la asi!nacin de columna recibe el nombre predeterminado secuencial SourceColu!nN, comenzando por SourceColu!n3. Si no se proporciona un nombre de tabla de ori!en en una asi!nacin de tablas, la asi!nacin de tabla recibe el nombre predeterminado secuencial Source,ableN, comenzando por Source,able3. Nota Es recomendable evitar la convencin de nombres de SourceColu!nN para una asi!nacin de columnas o Source,ableN para una asi!nacin de tablas, ya que es posible que el nombre proporcionado entre en conflicto con el nombre predeterminado de asi!nacin de columnas de la Colu!nMappingCollection o con el nombre de asi!nacin de tablas de la Data,ableMappingCollection. Si el nombre proporcionado ya e'iste, se iniciar una e'cepcin.
adapter.0ill(customersDataSet9 $Customers$)
*e crean dos tablas en el DataSet( Customers y Customers<. ,uede usar asignaciones de tabla para asegurarse de que la segunda se denomina Orders en lugar de Customers<. ,ara ello" asigne la tabla de origen de Customers< a la tabla Orders del DataSet" como se muestra en el e$emplo siguiente. 'opiar cdigo
3ea tambi4n
En esta seccin
Nota En la versin de .NE( )rame*or+ de /indo*s Server D..B se incluye una propiedad adicional para el DataReader, ;asRo(s, que permite determinar si el DataReader 1a devuelto al!9n resultado antes de realizar una lectura del mismo. En el e$emplo de cdigo siguiente se repite por un ob$eto DataReader y se devuelven dos columnas de cada fila. S'3T
'opiar cdigo
i+ (reader.EasFows) w!ile (reader.Fead()) Console.5rite6ine($<t{="<t{("$9 reader.Ret'nt?)(=)9 reader.RetString(()); else Console.5rite6ine($1o rows returned.$); reader.Close();
DataReader proporciona una secuencia de datos sin b8fer que permite a la lgica de los procedimientos procesar efica%mente y de forma secuencial los resultados procedentes de un origen de datos. DataReader es la me$or opcin cuando se trata de recuperar grandes cantidades de datos" ya que #stos no se almacenan en la memoria cac6#.
Cerrar el Data/eader
*iempre debe llamar al m#todo Close cuando 6aya terminado de utili%ar el ob$eto DataReader. *i Command contiene par4metros de salida o valores devueltos" #stos no estar4n disponibles 6asta que se cierre el DataReader. Tenga en cuenta que mientras est4 abierto un DataReader" #ste utili%a de forma e&clusiva el ob$eto Connection. No se podr4 e$ecutar ning8n comando para el ob$eto Connection 6asta que se cierre el DataReader original" incluida la creacin de otro DataReader.
Nota No llame a Close o Dispose para objetos Connection o DataReader ni para nin!9n otro objeto administrado en el mtodo Finalize de su clase. En un finalizador, libere slo los recursos no administrados que pertenezcan directamente a su clase. Si la clase no dispone de recursos no administrados, no incluya un mtodo Finalize en la definicin de clase. Para obtener ms informacin, consulte ecoleccin de elementos no utilizados.
// Assumes t!at connection is a valid SqlConnection o#Ject. SqlCommand command = new SqlCommand( $SA6AC, Categor&'D9 Categor&1ame 0FO% d#o.Categories;$ K $SA6AC, Amplo&ee'D9 6ast1ame 0FO% d#o.Amplo&ees$9 connection); connection.Open(); SqlDataFeader reader = command.ACecuteFeader(); do { Console.5rite6ine($<t{="<t{("$9 reader.Ret1ame(=)9 reader.Ret1ame(()); w!ile (reader.Fead()) Console.5rite6ine($<t{="<t{("$9 reader.Ret'nt?)(=)9 reader.RetString(()); " w!ile (reader.1eCtFesult()); reader.Close(); connection.Close();
Obtener in'ormacin del es+uema a partir del Data/eader
-ientras 6ay abierto un DataReader" puede utili%ar el m#todo 6etSc+ema1able para recuperar informacin del esquema acerca del con$unto actual de resultados. 6etSc+ema1able devuelve un ob$eto ataTable rellenado con filas y columnas que contienen la informacin del esquema del con$unto actual de resultados. Data1able contiene una fila por cada una de las columnas del con$unto de resultados. 'ada columna de una fila de la tabla de esquema est4 asociada a una propiedad de la columna que se devuelve en el con$unto de resultados. Column)ame es el nombre de la propiedad y el valor de la columna es el de la propiedad. En el e$emplo de cdigo siguiente se muestra la informacin del esquema de DataReader. S'3T 'opiar cdigo
Data,a#le sc!ema,a#le = reader.RetSc!ema,a#le(); +oreac! (DataFow row in sc!ema,a#le.Fows) { +oreac! (DataColumn column in sc!ema,a#le.Columns) Console.5rite6ine(column.Column1ame K $ = $ K row2column3); Console.5rite6ine(); "
Captulos de O E D"
-ediante OleDbDataReader puede recuperar con$untos $er4rquicos de filas o cap5tulos 9tipo D-18P&9:C:AP1&R de !LE ) y tipo adC+apter de A !: . 'uando se devuelve en forma de DataReader una consulta que incluye un cap5tulo" #ste se devuelve como una columna del DataReader y se e&pone como un ob$eto DataReader. Tambi#n se puede utili%ar DataSet de A !.NET para representar con$untos $er4rquicos de filas utili%ando relaciones entre tablas primarias y secundarias. ,ara obtener m4s informacin" consulte =tili%ar ata*ets en A !.NET.
En el e$emplo de cdigo siguiente se utili%a el proveedor -* ata*6ape para generar un cap5tulo con la columna de pedidos reali%ados por cada uno de los clientes de una lista. S'3T 'opiar cdigo
OleD#Connection connection = new OleD#Connection( $*rovider=%SDataS!ape;Data *rovider=S76O6ADB;$ K $Data Source=local!ost;'ntegrated Securit&=SS*';'nitial Catalog=nort!wind$); OleD#Command custC%D = new OleD#Command( $SEA*A {SA6AC, Customer'D9 Compan&1ame 0FO% Customers" $ K $A**A1D ({SA6AC, Customer'D9 Order'D 0FO% Orders" AS CustomerOrders $ K $FA6A,A Customer'D ,O Customer'D)$9 connection); connection.Open(); OleD#DataFeader custFeader = custC%D.ACecuteFeader(); OleD#DataFeader orderFeader; w!ile (custFeader.Fead()) { Console.5rite6ine($Orders +or $ K custFeader.RetString(()); // custFeader.RetString(() = Compan&1ame orderFeader = (OleD#DataFeader)custFeader.RetQalue()); // custFeader.RetQalue()) = Orders c!apter as DataFeader w!ile (orderFeader.Fead()) Console.5rite6ine($<t$ K orderFeader.Ret'nt?)(()); // orderFeader.Ret'nt?)(() = Order'D orderFeader.Close(); " custFeader.Close(); connection.Close();
,ara obtener acceso a un 1EF '=1*!1 devuelto desde un origen de datos de !racle" cree un OracleCommand para la consulta y agregue un par4metro de salida que estable%ca una referencia entre el 1EF '=1*!1 y la coleccin Parameters de OracleCommand. El nombre del par4metro debe coincidir con el nombre del par4metro 1EF '=1*!1 de la consulta. Estable%ca el tipo del par4metro en Oracle1ype Cursor. El m#todo &'ecuteReader del OracleCommand devolver4 un OracleDataReader para el 1EF '=1*!1. *i OracleCommand devuelve varios cursores 1EF '=1*!1" agregue varios par4metros de salida. ,uede tener acceso a los distintos cursores 1EF '=1*!1 llamando al m#todo OracleCommand &'ecuteReader . La llamada a &'ecuteReader devuelve un ob$eto OracleDataReader que 6aga referencia al primer 1EF '=1*!1. A continuacin" puede llamar al m#todo OracleDataReader )e'tResult para obtener acceso a los cursores 1EF '=1*!1 posteriores. Aunque los par4metros de la coleccin OracleCommand Parameters tengan el mismo nombre que los par4metros de salida de 1EF '=1*!1" OracleDataReader obtendr4 acceso a #stos en el mismo orden en el que se agregaron a la coleccin Parameters. ,or e$emplo" considere el siguiente paquete de !racle y" concretamente" el cuerpo del paquete. 'opiar cdigo
CFAA,A OF FA*6ACA *ACUARA C:FS*UR AS ,G*A ,-C:FSOF 'S FA0 C:FSOF; *FOCAD:FA O*A1-,5O-C:FSOFS (A%*C:FSOF O:, ,-C:FSOF9 DA*,C:FSOF O:, ,-C:FSOF); A1D C:FS*UR; CFAA,A OF FA*6ACA *ACUARA BODG C:FS*UR AS *FOCAD:FA O*A1-,5O-C:FSOFS (A%*C:FSOF O:, ,-C:FSOF9 DA*,C:FSOF O:, ,-C:FSOF) 'S BAR'1 O*A1 A%*C:FSOF 0OF SA6AC, ; 0FO% DA%O.A%*6OGAA; O*A1 DA*,C:FSOF 0OF SA6AC, ; 0FO% DA%O.DA*AF,%A1,; A1D O*A1-,5O-C:FSOFS; A1D C:FS*UR;
En el cdigo siguiente se crea un OracleCommand que devuelve los cursores 1EF '=1*!1 del paquete anterior de !racle mediante la adicin de dos par4metros de tipo Oracle1ype Cursor a la coleccin Parameters. S'3T 'opiar cdigo
OracleCommand cursCmd = new OracleCommand($C:FS*UR.O*A1-,5O-C:FSOFS$9 oraConn); cursCmd.*arameters.Add($A%*C:FSOF$9 Oracle,&pe.Cursor).Direction = *arameterDirection.Output; cursCmd.*arameters.Add($DA*,C:FSOF$9 Oracle,&pe.Cursor).Direction = *arameterDirection.Output;
El cdigo siguiente devuelve los resultados del comando anterior utili%ando los m#todos Read y )e'tResult del OracleDataReader. Los par4metros 1EF '=1*!1 se devuelven en orden. S'3T 'opiar cdigo
oraConn.Open(); OracleCommand cursCmd = new OracleCommand($C:FS*UR.O*A1-,5O-C:FSOFS$9 oraConn); cursCmd.Command,&pe = Command,&pe.Stored*rocedure; cursCmd.*arameters.Add($A%*C:FSOF$9 Oracle,&pe.Cursor).Direction = *arameterDirection.Output; cursCmd.*arameters.Add($DA*,C:FSOF$9 Oracle,&pe.Cursor).Direction = *arameterDirection.Output; OracleDataFeader reader = cursCmd.ACecuteFeader(); Console.5rite6ine($<nAmp 'D<t1ame$); w!ile (reader.Fead()) Console.5rite6ine(${="<t{("9 {)"$9 reader.RetOracle1um#er(=)9 reader.RetString(()9 reader.RetString())); reader.1eCtFesult(); Console.5rite6ine($<nDept 'D<t1ame$); w!ile (reader.Fead()) Console.5rite6ine(${="<t{("$9 reader.RetOracle1um#er(=)9 reader.RetString(()); reader.Close(); oraConn.Close();
En el siguiente e$emplo se utili%a el comando anterior para rellenar un DataSet con los resultados del paquete de !racle.
Nota Se recomienda que el usuario controle tambin cualquier conversin del tipo N70&E de #racle a un tipo vlido de .NE( )rame*or+ antes de almacenar el valor en DataRo( para evitar que se produzca una e'cepcin Overflo(E#ception. Puede utilizar el evento FillError para determinar si se 1a producido una e'cepcin Overflo(E#ception. Para obtener ms informacin sobre el evento FillError, vea (rabajar con eventos %ata:dapter. S'3T 'opiar cdigo
DataSet ds = new DataSet(); OracleDataAdapter adapter = new OracleDataAdapter(cursCmd); adapter.,a#le%appings.Add($,a#le$9 $Amplo&ees$); adapter.,a#le%appings.Add($,a#le($9 $Departments$); adapter.0ill(ds);
Al configurar DataReader para que utilice Se%uentialAccess debe tener en cuenta la secuencia en que va a tener acceso a los datos devueltos. El comportamiento predeterminado de DataReader" consistente en cargar una fila completa de datos en cuanto 6ay datos suficientes" permite tener acceso a ellos en cualquier orden 6asta que se lee la fila siguiente. *in embargo" al utili%ar Se%uentialAccess es necesario tener acceso a los campos que devuelve DataReader en el orden adecuado. ,or e$emplo" si la consulta devuelve tres columnas y la tercera es un )L!)" debe devolver los valores de los campos primero y segundo antes de tener acceso a los datos )L!) del tercer campo. *i trata de tener acceso al tercer campo antes que al primero o el segundo" puede que #stos de$en de estar disponibles. Esto se debe a que Se%uentialAccess cambia la forma en que el DataReader devuelve los datos" 6aciendo que lo 6aga de forma secuencial con lo que los datos de$an de estar disponibles en el momento en que el DataReader lee datos posteriores. 'uando intente obtener acceso a los datos del campo )L!)" utilice los descriptores de acceso con informacin de tipos 6et-ytes o 6etC+ars del DataReader" que llenan una matri% con los datos. En el caso de los datos de caracteres" puede utili%ar tambi#n 6etString> no obstante" si desea conservar los recursos del sistema" es me$or que no cargue un valor )L!) completo en una sola variable de cadena. En lugar de ello" puede especificar un tama7o determinado de b8fer para los datos que se van a devolver" as5 como la ubicacin de comien%o para leer el primer byte o car4cter de los datos devueltos. 6et-ytes y 6etC+ars devuelven un valor de tipo long que representa el n8mero de bytes o caracteres devueltos. *i pasa una matri% con valores null a 6et-ytes o 6etC+ars" el valor de tipo long devuelto contiene el n8mero total de bytes o caracteres del )L!). Tambi#n puede especificar un 5ndice de la matri% como posicin de comien%o para la lectura de datos.
E$emplo
En el siguiente e$emplo se devuelve el identificador y el logotipo del editor desde la base de datos de e$emplo pubs de -icrosoft *+L *erver ?///. El identificador de editor 9 pu#-id: es un campo de caracteres" mientras que el logotipo es una imagen de )L!). 'omo el campo logo es un mapa de bits" el e$emplo devuelve datos binarios mediante 6et-ytes. Tenga en cuenta que la necesidad de tener acceso a los datos de forma secuencial 6ace que en la fila actual de datos se tenga acceso al identificador de editor antes que al logotipo. '3 'opiar cdigo
// Assumes t!at connection is a valid SqlConnection o#Ject. SqlCommand command = new SqlCommand( $SA6AC, pu#-id9 logo 0FO% pu#-in+o$9 connection); // 5rites t!e B6OB to a +ile (;.#mp). 0ileStream stream; // Streams t!e B6OB to t!e 0ileStream o#Ject. Binar&5riter writer; // SiWe o+ t!e B6OB #u++er. int #u++erSiWe = (==; // ,!e B6OB #&te23 #u++er to #e +illed #& RetB&tes. #&te23 outB&te = new #&te2#u++erSiWe3; // ,!e #&tes returned +rom RetB&tes. long retval; // ,!e starting position in t!e B6OB output. long start'ndeC = =; // ,!e pu#lis!er id to use in t!e +ile name. string pu#'D = $$; // Open t!e connection and read data into t!e DataFeader. connection.Open(); SqlDataFeader reader = command.ACecuteFeader(CommandBe!avior.SequentialAccess); w!ile (reader.Fead()) { // Ret t!e pu#lis!er id9 w!ic! must occur #e+ore getting t!e logo. pu#'D = reader.RetString(=); // Create a +ile to !old t!e output. stream = new
0ileStream( $logo$ K pu#'D K $.#mp$9 0ile%ode.OpenOrCreate9 0ileAccess.5rite); writer = new Binar&5riter(stream); // Feset t!e starting #&te +or t!e new B6OB. start'ndeC = =; // Fead #&tes into outB&te23 and retain t!e num#er o+ #&tes returned. retval = reader.RetB&tes((9 start'ndeC9 outB&te9 =9 #u++erSiWe); // Continue w!ile t!ere are #&tes #e&ond t!e siWe o+ t!e #u++er. w!ile (retval == #u++erSiWe) { writer.5rite(outB&te); writer.0lus!(); // Feposition start indeC to end o+ last #u++er and +ill #u++er. start'ndeC K= #u++erSiWe; retval = reader.RetB&tes((9 start'ndeC9 outB&te9 =9 #u++erSiWe); " // 5rite t!e remaining #u++er. writer.5rite(outB&te9 =9 (int)retval O (); writer.0lus!(); // Close t!e output +ile. writer.Close(); stream.Close(); " // Close t!e reader and t!e connection. reader.Close(); connection.Close();
3ea tambi4n /e'erencia
b ata1eader escribe la clase DbDataReader" as5 como todos sus miembros. S%lDataReader escribe la clase S%lDataReader" as5 como todos sus miembros. OleDbDataReader escribe la clase OleDbDataReader" as5 como todos sus miembros. OdbcDataReader escribe la clase OdbcDataReader" as5 como todos sus miembros. OracleDataReader escribe la clase OracleDataReader" as5 como todos sus miembros.
Adem4s del m#todo Net*c6ema" el proveedor de datos de .NET Framework para !LE e&pone informacin de esquema mediante el m#todo Net!le b*c6emaTable del ob$eto
) tambi#n
!le b'onnection. 6etOleDbSc+ema1able toma como argumentos un !le b*c6emaNuid que identifica la informacin de esquema que se devuelve y una matri% de restricciones en esas columnas devueltas. 6etOleDbSc+ema1able devuelve una Data1able rellena con la informacin de esquema solicitada.
En esta seccin
using S&stem; using S&stem.Data; using S&stem.Data.SqlClient; class *rogram { static void %ain(string23 args) { string connectionString = RetConnectionString(); sing (SqlConnection connection = new SqlConnection(connectionString)) { // Connect to t!e data#ase t!en retrieve t!e sc!ema in+ormation. connection.Open(); Data,a#le ta#le = connection.RetSc!ema($,a#les$); // Displa& t!e contents o+ t!e ta#le. Displa&Data(ta#le); Console.5rite6ine($*ress an& e& to continue.$); Console.FeadUe&(); " " private static string RetConnectionString() { // ,o avoid
storing t!e connection string in &our code9 // &ou can retrieve it +rom a con+iguration +ile. return $Data Source=(local);Data#ase=Adventure5or s;$ K $'ntegrated Securit&=SS*';$; " private static void Displa&Data(S&stem.Data.Data,a#le ta#le) { +oreac! (S&stem.Data.DataFow row in ta#le.Fows) { +oreac! (S&stem.Data.DataColumn col in ta#le.Columns) { Console.5rite6ine(${=" = {("$9 col.Column1ame9 row2col3); " Console.5rite6ine($============================$); " " "
Especi'icacin de los !alores de restriccin
El segundo par4metro opcional del m#todo 6etSc+ema son las restricciones que se utili%an para limitar la cantidad de informacin de esquema devuelta. Este par4metro se pasa al m#todo 6etSc+ema como una matri% de cadenas. La posicin en la matri% determina los valores que puede pasar" y es equivalente al n8mero de restricciones. ,or e$emplo" en la siguiente tabla se describen las restricciones que admite la coleccin de esquemas GTablesG utili%ando el proveedor de datos de .NET Framework para *+L *erver(
N<!ero de restricciones D B A
,ara utili%ar una de las restricciones de la coleccin de esquemas GTablesG" basta con que cree una matri% de cadenas con cuatro elementos y coloque un valor en el elemento que coincida con el n8mero de restricciones. ,or e$emplo" para restringir las tablas devueltas por el m#todo 6etSc+ema a slo las que son propiedad de la funcin GdboG" estable%ca el segundo elemento de la matri% en GdboG antes de pasarlo al m#todo 6etSc+ema.
Nota $as colecciones con restricciones para S.lClient y OracleClient tienen una columna $ara!eterNa!e adicional. $a columna de valor predeterminado de restriccin si!ue a1" para la compatibilidad con versiones anteriores, pero actualmente se omite. Para reducir el ries!o de un ataque de inyeccin de S;$ al especificar valores de restriccin, es necesario utilizar consultas parametrizadas en lu!ar de sustitucin de cadenas. Nota El n9mero de elementos de la matriz debe ser menor o i!ual que el n9mero de restricciones admitidas en la coleccin de esquemas especificada o se iniciar una :r!umentE'ception. Puede 1aber un n9mero de restricciones inferior al m'imo. Se supone que las restricciones que faltan sern nulas 5sin restricciones6. ,uede consultar un proveedor administrado de .NET Framework para determinar la lista de restricciones admitidas mediante la llamada al m#todo 6etSc+ema con el nombre de la coleccin de esquemas con restricciones" que es G1estrictionsG. Esto devolver4 una Data1able con una lista de los nombres de colecciones" los nombres de restricciones" los valores predeterminados de restriccin y los n8meros de restricciones.
Ejemplo de restriccin de colecciones de es uemas En los siguientes e$emplos se muestra cmo utili%ar el m#todo 6etSc+ema del proveedor de datos de .NET Framework para la clase S%lConnection de *+L *erver para recuperar informacin de esquema de todas las tablas contenidas en la base de datos de e$emplo Adventure#or$s" y para restringir la informacin devuelta a slo las tablas propiedad de la funcin GdboG. S'3T 'opiar cdigo
using S&stem; using S&stem.Data; using S&stem.Data.SqlClient; class *rogram { static void %ain() { string connectionString = RetConnectionString(); using (SqlConnection connection = new SqlConnection(connectionString)) { //Connect to t!e data#ase9 and t!en retrieve t!e //sc!ema in+ormation. connection.Open(); string23 restrictions = new string2>3; restrictions2(3 = $d#o$; Data,a#le ta#le = connection.RetSc!ema($,a#les$9 restrictions); // Displa& t!e contents o+ t!e ta#le. Displa&Data(ta#le); Console.5rite6ine($*ress an& e& to continue.$); Console.FeadUe&(); " " private static string RetConnectionString() { // ,o avoid storing t!e connection string in &our code9 // &ou can retrieve it +rom a con+iguration +ile. return $Data Source=(local);Data#ase=Adventure5or s;$ K $'ntegrated Securit&=SS*';$; " private static void Displa&Data(S&stem.Data.Data,a#le ta#le) { +oreac! (S&stem.Data.DataFow row in ta#le.Fows) { +oreac! (S&stem.Data.DataColumn col in ta#le.Columns) { Console.5rite6ine(${=" = {("$9 col.Column1ame9 row2col3); " Console.5rite6ine($============================$); " " "