Download ADO conectado - entornosgraficos

Document related concepts

Microsoft SQL Server wikipedia , lookup

SQL wikipedia , lookup

Language Integrated Query wikipedia , lookup

ADO.NET wikipedia , lookup

Cursor (base de datos) wikipedia , lookup

Transcript
1
ADO.NET
La programación de BD en .NET utiliza unas cuantas clases en System.Data y sus espacios de nombres
hijos, lo que en conjunto se conoce como ADO.NET. Estas clases y sus métodos permiten recuperar
datos a partir de Microsoft SQL Server o una de las fuentes de datos OLE DB más genérica, procesarlos
y actualizar las tablas de la base de datos original.
Un proveedor de datos funciona como un puente entre una aplicación y la fuente de datos.
Los proveedores de datos permiten que una aplicación lea y escriba los datos almacenados en una
fuente de datos. En la actualidad ADO.NET soporta tres proveedores:
• OLE DB .NET. Permite acceder a una fuente de datos para la que exista un proveedor OLE DB,
aunque necesita un conmutador para administrar código no administrado.
Es compatible con los siguientes proveedores OLE DB:
- SQLOLEDB (para SQL Server)
- MSDAORA (para Oracle)
- Microsoft.Jet.OLEDB.4.0 (para Access)
• SQL Server .NET. Permite acceder a una fuente de datos SQL Server 7.0 o versiones posteriores.
• ODBC .NET. Funciona como un puente a una fuente ODBC. Actualmente sólo soporta
controladores ODBC de: Access, SQL Server y Oracle
El modelo de objetos ADO.NET
Los objetos que componen la arquitectura se han dividido en dos grupos:
- Los objetos que están incluidos en el Proveedor de datos .NET
- Y los que pertenecen a la arquitectura desconectada de ADO.NET
Proveedor de datos .Net
Connection
DataAdapter
(Datos sin conexión)
DataSet
Command
Parameter
DataReader
Connection. Su función es establecer una conexión con la fuente de datos.
Dispone, entre otros, de:
Propiedades:
ConnectinString. Cadena de caracteres con el nombre de la base de datos.
Métodos:
Open. Permite abrir la conexión
Close. Permite cerrar la conexión.
2
Command. Permite realizar una consulta a la base de datos, enviarle un comando (orden SQL) o
invocar alguno de los procedimientos almacenados.
Para ello, entre otros, dispone de distintos métodos Execute:
ExecuteNonQuery. Ejecuta la consulta de acción y devuelve el número de filas afectadas.
(Ej: INSET, UPDATE o DELETE SQL)
ExecuteReader. Ejecuta la consulta de selección, y devuelve el objeto DataReader que permite
acceder al resulset (Conjunto de filas y columnas).
(Ej: SELECT ...)
ExecuteEscalar. Ejecuta la consulta de selección y devuelve un valor escalar.
Propiedades que permiten crear el comando:
CommandText. Cadena con la sentencia SQL de la consulta.
Connection. Objeto Connection asociado al comando.
DataReader. Es el objeto que devuelve el método ExecuteReader. Representa un resulset de avance, de
sólo lectura.
Un resulset es el conjunto de filas y columnas obtenidas por la ejecución de un comando de selección.
DataReader dispone del método Read que permite obtener una nueva fila de resultados, la fila actual.
Una vez obtenida la fila se pueden realizar consultas a cada campo utilizando la propiedad Item, el
método GetValue, o los métodos Getxxxx con declaración de tipos (GetString, GetInt32, ...)
Propiedades:
Item(i). Sólo lectura. Permite acceder a cualquier campo, por su nombre o por el índice de su
columna (comienza por 0).
FieldCount. Obtiene el Nº de campos.
Métodos:
Read. Pasa a la fila siguiente y devuelve True si hay más filas y False si ha llegado al final del
resulset. Es decir, obtiene una nueva fila de resultados.
Close. Cierrar el objeto.
GetName(i). Recupera el valor del campo de índice i, de la fila actual.
GetValue(i). Obtiene el valor de un campo (en su formato nativo).
DataSet. Es el objeto que contiene una copia local de los datos leídos de una o varias fuentes de datos.
Su objetivo es guardar y procesar los datos. Se puede considerar como una base de datos relacional
disminuida, en memoria.
Está completamente desconectado de la fuente de datos, tanto física como lógicamente. Por ejemplo, se
puede rellenar un DataSet con uno o varios resulset procedentes de sentencias SQL sobre distintas bases
de datos, incluso de distintos proveedores; se puede rellenar un DataSet con una base de datos, o
incluso se puede rellenar con una tabla de datos que se haya creado por código.
Una vez cargados los datos en el objeto DataSet, se puede:
- Crear relaciones entre los diferentes resulset.
- Navegar por los resulset
La independencia de la fuente de datos específica se consigue gracias al objeto DataAdapter. Este es el
objeto que carga los datos en el DataSet y es capaz de actualizar una fuente de datos con los datos que
la aplicación ha agregado, eliminado o modificado.
DataAdapter. Funciona como un puente entre los objetos Connection y DataSet. Puede recuperar y
actualizar datos de un origen a través de sus métodos Fill y Update.
Fill. Copia los datos del origen de datos al DataSet.
Update. Mueve los datos del DataSet a la base de datos.
Actualiza la BD, añade, elimina o actualiza sus filas.
3
Espacios de nombres
Los diferentes proveedores utilizan diferentes espacios de nombres y también utilizan diferentes
nombres para los objetos.
Para utilizar en las aplicaciones estos espacios de nombres se deben importar. Por lo tanto se utilizará
alguna de las siguientes sentencias dependiendo del proveedor de datos que se desee utilizar:
Imports SystemData. Contiene los objetos DataSet y sus derivados: DataTable, DataRow,
DataRelation
Imports System.Data.SqlClient. Contiene objetos del proveedor SQL Server .Net: SqlConnection,
SqlCommand, SqlDataReader y SqlDataAdapter
Imports.System.OleDb. Contiene objetos del proveedor OLE DB .NET: OleDbConecction,
OleDbCommand, OleDbDataReader y OleDbDataAdapter
Nosotros utilizaremos OLE DB. Se describen los objetos con sus miembros para este proveedor.
El Objeto Connection
Tanto si se trabaja en modo conectado como sin conexión, lo primero que se debe hacer con una fuente
de datos es abrir una conexión en ella. Esto implica que se crea un objeto Connection que conecta con
la base de datos especificada.
Relación incompleta de miembros soportados por OLE DB.
Propiedades:
ConnectinString. Cadena utilizada para conectar con la fuente de datos.
ConectionTimeout. Número de segundos después del cual una conexión fallida se interrumpe. Es de
sólo lectura, ya que este valor se configura en la propiedad ConnectionString. El valor
predeterminado es de 15 segundos.
DataBase. Devuelve el nombre de la base de datos especificada en la propiedad ConnectionString. Sólo
lectura.
DataSource. Devuelve el nombre del atributo Data Source, especificado en ConnectionString. Sólo
lectura.
Provider. Devuelve el valor del atributo Provider (proveedor) especificado en ConnectionString. Sólo
lectura.
ServerVersion. Devuelve la versión del servidor conectado en formato xx.yy.zzzz o una cadena vacía si
no puede obtener esta información
State. Devuelve es estado actual de la conexión. Es un campo de bit codificado. Puede ser un valor de
la enumeración ConnectionState (Closed, Open, ...)
Métodos:
Open. Abre la conexión.
Close. Cierrra la conexión y libera todas las fuentes de datos asociadas.
BeginTransation. Comienza una transacción de base de datos utilizando el nivel de aislamientos
especificado en el argumento opcional.
ChangeDataBase. Cambia el nombre de la base de datos para la conexión actual
CreateCommand. Crea un objeto Command asociado a la conexión actual.
Sucesos:
StateChange. Se activa cuando la propiedad State cambia.
4
Propiedad ConnectionString . Cadena de caracteres que define el tipo de la BD a la que está conectado
(Proveedor), su ubicación, su nombre y otros atributos separados por ;
Atributos:
Provider. Especifica el nombre del proveedor OLE DB utilizado:
- SQLOLEDB (para SQL Server)
- MSDAORA (para Oracle)
- Microsoft.Jet.OLEDB.4.0 (para Access)
Data Source. Especifica dónde está la base de datos. Puede ser:
- La ruta y nombre de una base de datos Access.
- El nombre de la máquina en la que está la base de datos Oracle o SQL Server.
User ID. Nombre del usuario de una cuenta válida para la BD.
Password. Contraseña de esa cuenta.
Procedimientos de apertura de una conexión a una base de datos.
La apertura de la conexión es imprescindible tanto en modo desconectado como conectado
1. Crear una instancia del objeto Connection.
2. Establecer la cadena de conexión.
3. Abrir la conexión.
1. Crear una instancia del objeto Connection.
Este objeto puede devolver eventos o no.
Dim Cn As New OleDbConnection
-o-
Dim WithEvents Cn As New OleDbConnection
2. Establecer la cadena de conexión.
El atributo Data Source de la cadena de conexión contiene el nombre de la BD con su ruta de
acceso. Si la BD se encuentra en el mismo directorio que el archivo .exe del proyecto, no es
necesario escribir la ruta.
En este caso Biblio.mdb se encuentra en el subdirectorio bin\Debug del proyecto
Dim CadenaConexion As String
CadenaConexion = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Biblio.mdb;"
Cn.ConnectionString = CadenaConexion
Los pasos 1 y 2 se pueden agrupar:
Dim CadenaConexion As String
CadenaConexion = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Biblio.mdb;"
Dim Cn = New OleDbConnection(CadenaConexion)
3. Abrir la conexión.
Cn.Open()
Al abrir la conexión conviene comprobar su estado y controlar los errores.
Dim cadena As String
Try
Cn.Open()
cadena = Cn.State.ToString
Me.TxtConexion.Text = cadena
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
Procedimientos de Cierre de una conexión.
If Cn.State = ConnectionState.Open Then Cn.Close()
El método Close no da error si la conexión estaba cerrada.
Cn.Close()
5
El Objeto Command
Una vez abierta una conexión se puede elegir entre trabajar en modo conectado o desconectado.
En modo conectado, lo normal es crear un objeto Command que contenga una consulta a una base de
datos y a continuación ejecutar el método Executexxxx que corresponda con el tipo de consulta:
De selección para obtener datos de la BD
De acción para actualizar datos en la BD
Propiedades:
Connection. Obtiene o establece el objeto Connection de este comando.
CommandText. String. Obtiene o establece la instrucción SQL, nombre de la tabla o
procedimiento almacenado, que se va a ejecutar en el origen de datos.
CommandType. Obtiene o establece un valor que indica el tipo de consulta. Es decir, cómo se
interpreta la propiedad CommandText. Sus valores pueden ser:
Text. Sentencia SQL (por defecto)
StoredProcedure. Procedimiento almacenado
TableDirec. Tabla
CommandTimeout. Integer. Obtiene o establece el tiempo de espera hasta que se interrumpa el
intento de ejecutar un comando y se genere un error.
Parameters. Colección de parámetros del comando.
Transaction. Obtiene o establece el objeto Transaction correspondiente a la transacción en la que se
ejecuta este comando.
UpdateRowSource. Obtiene o establece la manera en que se aplican los resultados del comando
a DataRow cuando lo utiliza el método Update del DataAdapter. (Sólo en
desconectado)
Métodos:
Cancel. Cancela la ejecución del comando.
ResetCommandTimeout. Restablece el valor predeterminado de la propiedad CommandTimeout (30
segundos).
Para lectura de datos:
ExecuteNonQuery. Ejecuta la consulta de acción y devuelve el número de filas afectadas.
ExecuteReader. Ejecuta una consulta de selección y devuelve un objeto DataReader que permite
acceder al resulset (Conjunto de filas y columnas obtenidos por la consulta).
Este método puede incluir un valor opcional CommandBehavior.
CommandBehavior es una enumeración que proporciona una descripción de los resultados de
la consulta y de sus efectos en la base de datos.
Se puede utilizar una combinación bit a bit de sus valores. Por ejemplo si se devuelve una única
fila o si se debe cerrar la conexión cuando finalice el método, etc.
ExecuteScalar. Ejecuta la consulta y devuelve un valor escalar. Es decir, devuelve la primera
columna de la primera fila del conjunto de resultados devuelto por la consulta.
Funciona con cualquier consulta SQL y devuelve el primer campo de la primera
fila.
Para consultas parametrizadas:
CreateParameter. Crea un objeto Parameter conectado a este comando parametrizado.
6
Procedimientos de creación y ejecución de comandos
El procedimiento general es el siguiente:
1º. Abrir la conexión
2º. Crear y ejecutar el comando
3º. Cerrar la conexión
Crear el comando:
1. Crear una instancia del objeto Command
Dim Cmd As New OleDbCommand
2. Establecer, al menos, las propiedades CommandText y Connection
Por defecto se va a interpretar que CommandText contiene una sentencia SQL, si no es así
también hay que establecer CommandType con el valor correspondiente.
Dim Sql As String
Sql = "Select ..." ó "Insert ..." ó "Update... " ó "Delete ..."
With Cmd
.CommandText = Sql
.Connection = Cn
End With
Los pasos 1 y 2 se pueden agrupar:
Dim Sql As String
Sql = "Select ..." ó "Insert ..." ó "Update... " ó "Delete ..."
Dim Cmd As New OleDbCommand(Sql, Cn)
Ejecutar el comando:
Para ejecutar el comando se utilizará el método adecuado en función de la consulta establecida.
Es recomendable controlar los errores.
Las consultas de acción: Insert, Delete, Update, devuelven el número de registros afectados:
Try
Dim NregAfectados As Integer = Cmd.ExecuteNonQuery
'mostrar el resultado
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
'Cierra siempre la conexión
'Cn.Close()
End Try
Las consultas de selección que devuelven un valor escalar: "Select Count(*) from ...", ...
Dim Num As Integer = CInt(Cmd.ExecuteScalar)
Las consultas de selección que devuelven un objeto DataReader: "Select * from ..."
1. Declarar el objeto DataReader
Dim Dr As OleDbDataReader
2. Asignar al objeto DataReader el resultado de la ejecución del comando.
Es conveniente comprobar si la conexión está abierta
Try
If Cn.State = ConnectionState.Open Then
Dr = Cmd.ExecuteReader
End If
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
7
Objeto DataReader. Obtiene un resulset resultado de la ejecución de un comando de selección.
Un objeto DataReader permite la navegación hacia adelante (Foward Only) y en modo sólo lectura
(Read Only), de los registros devueltos por una consulta (resulset).
Los DataReader permanecen conectados durante todo el tiempo que realizan el recorrido por los
registros que contienen, ya que efectúan la lectura de la fuente de Datos (BD) fila a fila (registro a
registro).
El uso de este objeto puede incrementar el rendimiento de una aplicación y reducir la carga del sistema
ya que solo se almacena en el buffer del Cliente una sola fila (registro) cada vez.
No es posible ejecutar ningún comando en una conexión mientras un obj DataReader esté activo en esa
conexión. Por lo tanto, se debe cerrar un DataReader, cuando ya no se tienen que procesar más filas,
para liberar recursos y dejar disponible la conexión para otros comandos.
Propiedades:
IsClosed. True si DataReader está cerrado.
Item(i). Sólo lectura. Devuelve el valor de un campo de la fila actual.
Permite acceder a cualquier campo, por su nombre o por el índice de su columna (comienza por
0).
Es el miembro predeterminado, por lo que se puede omitir.
dr.Item(IdiceColumna)
dr(IdiceColumna)
dr.Item(“NombreCampo”)
FieldCount. Obtiene el Nº de campos de la fila actual.
HasRows. Bolean. Obtiene un valor que indica si el DataReader contiene alguna fila.
RecordsAffected. Devuelve el número de filas insertadas, eliminadas o actualizadas por la instrucción
SQL
Métodos:
Read. Desplaza el cursor actual al siguiente registro del resulset permitiendo obtener los valores del
mismo.
Pasa a la fila siguiente y devuelve True si hay más filas y False si ha llegado al final del
resulset.
La posición del objeto DataReader en el momento inicial es antes del primer registro, por lo
tanto para recorrer un objeto DataReader debemos comenzar con una llamada al método
Read(), y así situarnos en el primer registro.
Close. Cierrar el objeto, libera todos los recursos asignados a él y hace que la conexión esté disponible
para otros comandos.
NextResult. Pasa al siguiente resulset y devuelve True si hay otro resulset.
Desplaza el puntero actual al siguiente conjunto de registros cuando la sentencia SQL
devuelve más de un conjunto de registros (Más de una sentencia Select separada por punto y
coma). Como los que pueden devolver un procedimiento almacenado o un procesamiento por
lotes.
GetName(i). Recupera el nombre del campo de índice i.
GetOrdinal(NombreCampo). Devuelve el índice de la columna correspondiente al nombre de campo
pasado como argumento.
8
Métodos de la fila actual leída con Read
IsDBNull(i). Devuelve True si el campo de índice i contiene un valor DBNul.
If Dr.IsDBNull(i) = True Then ...
GetValue(i). Obtiene el valor de un campo (en su formato nativo).
Da error si el campo es nulo
'recupera el valor de un campo
If Dr.IsDBNull(0) = False Then
Me.TextBox1.Text = Dr.GetValue(0).ToString
End If
GetValues(Matriz). Devuelve los valores de todos los campos de la fila actual en una matriz de objetos.
Este procedimiento es más lento que el anterior.?
Dim cadena As String
Dim TbCampos(Dr.FieldCount - 1) As Object
'obtiene todos los campos
Dr.GetValues(TbCampos)
'itera todos los campos TbCampos(i)
cadena = ""
For i = 0 To Dr.FieldCount - 1
If Not IsDBNull(TbCampos(i)) Then
cadena = cadena & TbCampos(i) & "-"
End If
Next
Me.TextBox1.Text = cadena
Getxxxx(i). Recupera el valor del campo, con declaración de tipo. (GetString, GetInt32, ...)
Los Datos obtenidos por un DataReader están en el formato binario propio del proveedor de
datos. Estos valores se deben convertir a los tipos adecuados, para ello DataReader dispone de
un conjunto de métodos que permiten obtener los valores de los campos en el tipo de datos
deseado.
GetBoolean(i), GetInt32(i), GetString(i), GetChar(i), etc.
GetFieldsType(i). Devuelve el objeto System.Type del tipo de campo.
9
Procedimientos de lectura del resulset
El procedimiento general es el siguiente:
1º.
Abrir la conexión
2º.
Crear y ejecutar el comando
3º.
Leer los datos, mostrarlos o procesarlos ...
4º.
Cerrar la conexión
Leer los datos y mostrar el nombre de los campos y sus valores:
El número y nombre de los campos se puede obtener después de ejecutar el comando.
El valor de los campos se obtiene al ejecutar el método Read del DataReader
1. Leer la siguiente fila.
Cerrar el lector DataReader cuando no haya más filas
'lee la siguiente fila
If Dr.Read = False Then
MessageBox.Show("no hay más registros")
Dr.Close()
Else
'mostrar los resultados
End if
2. Mostrar los resultados
'mostrar el nombre de los campos
Label1.Text = Dr.GetName(1)
Label2.Text = Dr.GetName(2)
Label2.Text = Dr.GetName(3)
...
'mostrar el valor de los campos
Txt1.Text = Dr.Item(1).ToString
Txt2.Text = Dr.Item(2)
Txt3.Text = Dr(3)
...
If Dr.IsDBNull(4) = False Then
Txt4.Text = Dr.GetValue(4).ToString 'da error si el campo es nulo
End If
Los pasos 1 y 2 se pueden agrupar:
Dim TbLabel() As Label = {Me.Label2, Me.Label3, Me.Label4,...}
Dim TbCaja() As TextBox = {Me.TextBox1, Me.TextBox2, Me.TextBox3, ...}
If Dr.Read = False Then
MessageBox.Show("no hay más registros")
Dr.Close()
Else
'mostrar resultados
For i = 0 To Dr.FieldCount - 1
'mostrar nombres de campos
TbLabel(i).Text = Dr.GetName(i)
'mostrar valor de los campos
TbCaja(i).Text = Dr.Item(i).ToString
Next
End if
10
Para leer todos los registros:
'recupera el nombre de los campos y los muestra
For i = 0 To Dr.FieldCount - 1
Me.TxtNombreCampos.AppendText(Dr.GetName(i) & "
Next
")
'recupera el valor de los campos del resulset, fila a fila
'y los muestra en una lista fija
Dim cadena As String
Do While Dr.Read = True
cadena = ""
For i = 0 To Dr.FieldCount - 1
cadena = cadena & Dr.Item(i) & "-"
Next
Me.LstCampos.Items.Add(cadena)
Loop
11
Consultas parametrizadas.
En muchas ocasiones es necesario utilizar consultas SQL con valores de campos variables (o
parámetros). Es decir, un campo podrá tomar, en tiempo de ejecución, distintos valores; como, por
ejemplo, el valor asignado por el usuario.
Ejemplos. De la BD Biblio.mdb:
- Obtener el título de los libros escritos por un autor seleccionado por el usuario.
- Obtener los datos de los libros publicados por la editorial seleccionada por el usuario.
- Obtener el título de los libros publicados, en el año seleccionado por el usuario, por la editorial
seleccionada también por el usuario.
En estos casos el comando que se ha de crear ha de tener parámetros, y utilizar, en la consulta SQL,
unos signos u otros como marcadores de posición. La sintaxis depende del proveedor de datos.
Los comandos parametrizados son útiles cuando se tiene que realizar el mismo tipo de consulta más de
una vez, con diferentes valores en los parámetros.
Procedimiento de utilización de comandos parametrizados:
1. Crear el comando con los marcadores de posición
2. Configurar la colección de parámetros
3. Ejecutar el comando.
Crear el comando con los marcadores de posición
Dependiendo del proveedor de datos la sentencia SQL utilizada tendrá unos marcadores de posición u
otros.
Para el proveedor SQL Server .NET, se utiliza @ como marcador de posición.
Sql = "Select * From Titles Where PubId=@ParName"
Para el proveedor OLE DB .NET, se utiliza ? como marcador
Sql = "Select Title From Titles Where PubID=?
And [Year Published]=?"
Aunque los procedimientos son similares, no son iguales. Aquí se va a describir los utilizados para el
proveedor de datos OLE DB
'Crea el comando con signos de interrogación como marcadores de posición
Dim Sql As String
Sql = "Select Title From Titles Where PubID=? And [Year Published]=?"
Dim Cmd As OleDbCommand
Cmd = New OleDbCommand(Sql, Cn)
12
Configurar la colección de parámetros
Se deben crear tantos objetos Parameter como parámetros tenga la consulta SQL y luego agregarlos a la
colección Parameters del objeto Command, en el mismo orden en que aparecen los parámetros en el
comando SQL.
Existen 3 modos de crear un objeto Parameter:
a) Utilizando el constructor del objeto Parameter
'define el parámetro
Dim Par As New OleDbParameter("ParIdEditorial", OleDbType.Integer)
Par.Value = 1 'asigna valor inicial. No es necesario
Cmd.Parameters.Add(Par) 'añade el parámetro a la colección de parámetros
'define el 2ºparámetro
Dim Par2 As New OleDbParameter("ParAñoPubli", OleDbType.SmallInt)
Cmd.Parameters.Add(Par2) 'añade el parámetro a la colección de parámetros
b) Utilizando el método CreateParameter del objeto Command
No es obligatorio definir ni el nombre del parámetro ni el tipo.
'configura el 1er parámetro
Dim Par As OleDbParameter 'declara el parámetro
Par = Cmd.CreateParameter 'crea el parámetro
Par.Value = 1 ' no es necesario
Cmd.Parameters.Add(Par) añade el parámetro a la colección
'configura el 2º parámetro
Dim Par As OleDbParameter = Cmd.CreateParameter
Cmd.Parameters.Add(Par)
c) Invocando al nuevo método AddWithValue de la colección Parameters
Introduce nombre y valor en el método AddWithValue de la colección Parameters
'invoca al método AddWithValue
Cmd.Parameters.AddWithValue("ParIdEditorial", 1)
Cmd.Parameters.AddWithValue("ParAñoPubli", 1992)
Ejecutar el comando
- Asignar valor a los parámetros
- Ejecutar el comando
'Asigna valor a los paarámetros
Dim Valor1 As Integer = Me.TextBox1.Text
Cmd.Parameters(0).Value = Valor1
Dim Valor2 As Short = Me.TextBox2.Text
Cmd.Parameters(0).Value = Valor2
'Ejecuta el comando
Dim Dr As OleDbDataReader
Dr = Cmd.ExecuteReader
'obtiene el resultado