sábado, 1 de marzo de 2008

LinQ - Introducción


LinQ to Sql (Arquitectura de capas):


Antes de que pasen a los ejemplos que he puesto de LINQ, me gustaría hablar un poco de este:


LINQ sigla de Language-Integrated Query o Lenguaje Integrado de Consulta, nos permite definir un estándar de consultas y de transacción de datos de una forma común, por que digo común, por que podemos consultar información de una entidad de una base de datos de forma muy parecida a como podemos consultar un dato de un arreglo (Array) o, como consultar la información de un nodo de un Xml, ya que LINQ cuenta con 5 tipos de objetos, los cuales son:

  • LinQ to Sql
  • LinQ to Entidades
  • LinQ to Objetos
  • LinQ to Dataset
  • LinQ to Xml

En su primera versión, que fue Beta definida en C#, LinQ presentaba una ventaja a la hora de rescatar la información, ahora en su versión incluída en el Framwork 3.5 y habilitada para C# y Visual Basic, LinQ nos habre un espectro mayor y homogenio para realizar consultas y transacciones.


El esquema en el que está montado LinQ se puede observar en la siguiente imagen (rescatada de:
http://msdn.microsoft.com/msdnmag/issues/07/06/CSharp30/default.aspx?loc=es )


Ahora que estamos enterados de modo general que es LINQ, podemos pasar a los ejemplos, pero si desean más info sobre los tipos que se pueden declarar pueden ir a la URL en donde rescaté la imagen, pero para su comodidad se las vuelvo a escribir:

http://msdn.microsoft.com/msdnmag/issues/07/06/CSharp30/default.aspx?loc=es

LinQ to Sql - Data label


LinQ to Sql (Arquitectura de capas):



Este artículo constará de tres partes:
  • Definición de Modelo de Datos Físico y Capa de Datos
  • Definición de Capa de negocios.
  • Definición de una interfaz de usuario, en este caso windows, pero puede ser web, recordemos que usamos capas (Portable y Reutilizable).
Como lo prometido es deuda he aquí un artículo de programación a tres capas con LinQ to sql y programado a objetos, pero antes debemos hablar un poco de que es la programación OO y que es LinQ.

LinQ (Language-Integrated Query o Lenguaje Integrado de Consulta), es el nuevo compilador que en un inicio era de C#, incluído en su versión Beta, en el Framework 3.0 y correspondía a la versión 3.0 de C#. En la actualidad LINQ no solo esta definido para C# sino que también para Visual Basic, en su versión incluída en el Framework 3.5, lo cual nos permite potenciar nuestros desarrollos en VB y C#.

Existen varias utilidades definidas para linq, como: LinQ to Sql, LinQ to DataSet, LinQ to Entities, LinQ to Xml y LinQ to Object.
Yo me centraré en este artículo en LinQ to Sql y, construiremos una capa de datos con esta nueva utilidad que nos ofrece el framework 3.5


En una segunda explicación, debemos saber que la programación orientada a objetos es resultado de un análisis y diseño de solución, debemos separar muy bien el concepto de objeto ya que se tiende a confundir los objetos que ofrece la herramienta de desarrollo con los objetos que se obtienen de un análisis y diseño.

Cuando hablamos de un botón estamos hablando de un control asociado a una clase que hereda de una clase superior que se encuentra definida en un Framework X, estas clases nos apoyarán en la programación de las interfaces, por decir algo, no debemos perder tiempo en estas clases ya que estan definidas (Un viejo jefe tuvo una discución de 2 horas conmigo sobre el objeto botón jejejeje "El que sabe sabe y el que no es jefe").

En cambio cuando hablamos de un objeto como el de persona, este nos dará como resultado una clase que tendrá asociada propiedades y métodos.

Los métodos estarán definidos y distribuídos en las capas o incluso, los métodos serán de tres capas, por eso es que a veces vemos en diferentes capas, métodos con el mismo nombre dentro de objetos de distintas capas (Con el mismo nombre, esto no es un error, Si!!! una programación OO define que en cada capa este el mismo nombre de Clase). Si bien es cierto, que las clases de apoyo son importantes, no representan gran importancia dentro de una programación orientada a objetos, ya que los objetos que realmente son importantes son los que se definen en el análisis y diseño y nos generarán la Base de datos, con sus entidades, y las clases y métodos que se distribuirán en cada una de las capas, es decir, si tenemos una clase persona y tenemos tres capas: Base de datos, capa de datos, capa de negocios, en la base de datos tendremos las entidades que se generarán resultado del modelo conceptual(Que dará como origen el modelo de datos y el modelo de clases) y, luego tenemos las clases de cada capa, es decir, si definimos una clase en el diseño, esta clase debe estar reflejada en la capa de datos y en la capa de negocios con el mismo nombre y con diferencias de métodos, esto quedará más claro cuando definamos nuestras capas.

Bueno chicos, este artículo no está orientado a enseñarles a programar OO, existen varios libros para eso, lo malo es que muy pocas personas entienden los conceptos de realizar análisis y diseño orientados a los objetos, por lo cual si la programación OO a objeto no está clara, es porque el Analista no sabe definir bien los objetos y modelo de clases. Es facil hablar de Análisis y Diseño OO, pero es realmente dificil definir un buen documento de este tipo, aunque existan muchas herramientas de apoyo (Recuerden Herramientas de apoyo, la lógica esta siempre del lado del Coeficiente intelectual).

Bueno ahora a lo suyo, modelemos una capa de datos con LINQ.

2 - Definición de Capa de datos

Debemos saber que LINQ to SQL permite acceder de dos formas a Bases de Datos, una es interactuando con las entidades directamente y otra es realizando llamadas a procedimientos almacenados definidos en una Base de Datos.


NOTA: En la actualidad LINQ solo funciona para SQL (Su mismo nombre lo dice LINQ to SQL), vamos a ver si los amigos de Microsoft sacan otros tipos de LINQ para Bases de Datos.


En esta parte definiremos los script de creación de tablas que utilizaremos para crear nuestras Bases de Datos, esto debe ser en SQL Server, preferentemente en 2005.


Bueno, la Base de Datos la llamaremos LINQ y los script de creación de tabla los entrego a continuación:

CREATE TABLE [lnqEmpleado](
[empCodigo] [int] IDENTITY(1,1) NOT NULL,
[empNombre] [varchar](70) NOT NULL,
[empApellidoPrimero] [varchar](70) NOT NULL,
[empApellidoSegundo] [varchar](70) NOT NULL,
[empFechaActivacion] [datetime] NOT NULL,
[empEstado] [char](1) NOT NULL,
CONSTRAINT [PK_lnqEmpleado] PRIMARY KEY CLUSTERED
(
[empCodigo] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
)

CREATE TABLE [lnqUsuario](
[usuCodigo] [int] IDENTITY(1,1) NOT NULL,
[empCodigo] [int] NOT NULL,
[usuLogin] [char](10) NOT NULL,
[usuClave] [char](10) NOT NULL,
[usuEstado] [char](1) NOT NULL,
CONSTRAINT [PK_lnqUsuario] PRIMARY KEY CLUSTERED
(
[usuCodigo] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
)
ALTER TABLE [lnqUsuario]
WITH CHECK ADD CONSTRAINT [FK_lnqUsuario_lnqEmpleado]
FOREIGN KEY([empCodigo]) REFERENCES [lnqEmpleado] ([empCodigo])

ALTER TABLE [lnqUsuario] CHECK CONSTRAINT [FK_lnqUsuario_lnqEmpleado]



LinQ to Sql - Data acces label


LinQ to Sql (Arquitectura de capas):


En esta parte del artículo veremos como utilizar el objeto LinQ to sql, comprender como trabajaremos, es decir, como definiremos la estructura de nuestro proyecto, esto se hará utilizando bibliotecas de clases.

En esta fase veremos como interactuar con las entidades de la Base de Datos directamente con LinQ to Sql, es decir, la lógica transaccional la definiremos en nuestras clases que atenderán los objetos principales.
Para los que han desarrollado antes en .Net de buena forma, sabran que definir una Capa de Datos y una Capa de Negocios en bibliotecas de clase, permite mayor portabilidad, reuzabilidad y permite migrar de una versión a otra sin tener que afectar de gran forma los niveles de interfaces de usuario.


No voy a explicar este tema porque los buenos programadores no lo necesitan, solo me detendré a explicar el objeto LinQ to Sql y las cosas que haremos con este



En el caso de que no tengan VS2008 veremos a mediados de mes de Marzo como crear una capa de Datos y de negocio con Visual Studio 2005, pero el interez que tengo ahora es de definir una capa con LINQ to Sql.

El primer paso será habrir nuestro Visual Studio 2008 y seleccionar la opción crear proyecto nuevo, en este caso, crearemos un proyecto de bibliotecas de clase en C#. Pueden llamarlo como quieran, yo lo llamaré "CapaDato" y la solución la llamare WinApp.

Ya creado el proyecto, agregaré el objeto "LINQ TO Sql Classes" a la solución, yo lo he llamado dcPrueba.dbml dc asociado a "Data Clase", pero como vamos a trabajar con el objeto usuario, podrían llamarlo dcUsuario, pero deben tener que considerar que, deben cambiar las llamadas de nombre, ya que yo utilizaré dcPrueba.

Hasta ahora todo bien, veremos que se ha desplegado un diseñador del objeto LinQ to Sql Classes, que muestra dos zonas, una es para asociar las entidades que utilizaremos y que definirán las estructuras a utilizar en las capas que definiremos más adelante. En la zona que aparece a la derecha del diseñador del objeto LinQ to Sql Classes, se agregan los métodos de Bases de Datos (Procedimientos almacenados), que se utilizarán. Nosotros solo trabajaremos en este artículo con accesos directos y al final de este, veremos como consumir los procedimientos almacenados. La interfaz de diseño se puede observar a continuación:


El siguiente paso será asociar las dos entidades que hemos creado en la base de datos a la sección de creación de clases de objetos, para ello crearemos una conexión a la Base de Datos LINQ.




Luego arrastraremos las dos entidades a la sección derecha del diseñador del objeto LinQ to Sql Classes, quedando este como se muestra a continuación:




Si se observa, en el explorador de clases se mostrarán tres clases, dos asociadas a las estructuras de las entidades, que constituyen el tratamiento de datos para el objeto y, una que presenta los métodos de diseño y transacción con la Base de Datos. Si observamos desde el explorador de soluciones solo veremos un archivo, que es el que hemos creado en el diseñador del objeto LinQ to Sql Classes, pero dentro de este existe un archivo .designer.cs que presenta las estructuras de las clases que se observan dentro del explorador de clases, este archivo es dcPrueba.designer.cs o, para los que definieron dcUsuario sera dcUsuario.designer.cs

Creando un Data Access Label

Bueno hasta ahora tenemos construida la lógica de estructura y la lógica que soportará las transacciones en el diseñador del objeto LinQ to Sql Classes (todo en unos pocos pasos). Lo siguiente será definir las rutinas de acceso a datos, para ello agregaremos a la solución una clase que llamaremos dalUsuario.

En la clase dalUsuario (dal por data access label), definiremos los métodos de consulta, inserción, actualización y eliminación de registros, reutilizando, en este caso los métodos creados por el diseñador. Pero antes de hacer esto, debemos entender el comportamiento del objeto.

Si creamos un objeto, en donde rescatamos los detalles de factura y, tenemos definidos en el objeto la estructura de clases de detalle de facturas y de factura. Al buscar el detalle de esta, LinQ to Sql retornará también la cabecera de la factura asociada a los detalles, según la estructura definida, por lo cual, si queremos solo los datos específicos de una estructura deberemos filtrar estos.

Existen dos formas de retornar la información:

  • Recorriendo lo rescatado y creando una lista de tipo de clase o,
  • Devolviendo directamente el resultado cargado a una variable según una estructura creada.

Bueno en este ejemplo haremos la primera, pero les pondré el código y les daré las indicaciones para realizarlo de la segunda forma:

Recorriendo lo rescatado con LinQ to SQL y creando una lista

Lo primero que debemos hacer es crear dentro del archivo dalUsuario.cs, una nuava clase pero fuera del espacio de definición de la clase dalUsuario, es decir en el namespace la siguiente definición de estructura de clase:


public class clsUsuario {
private int _usuCodigo;
private string _usuLogin;
private string _usuClave;
private char _usuEstado;
public int Codigo{
get { return _usuCodigo; }
set { _usuCodigo = value; }
}
public string Login {
get { return _usuLogin; }
set { _usuLogin = value; }
}
public string Password {
get { return _usuClave; }
set { _usuClave = value; }
}
public char Estado {
get { return _usuEstado; }
set { _usuEstado = value; }
}
}

Esta estructura será utilizada tanto para crear la lista a retornar, como para crear el objeto de búsqueda de la segunda opción mencionada "Devolviendo directamente el resultado cargado a una variable según una estructura creada".

Bueno, como dijimos, LinQ to SQL permite realizar transacciones desde dos perspectivas, por consultas desde LINQ to sql y las entidades o desde procedimientos almacenados que retornarán la información. Para cualquiera de los dos casos deben existir estructuras de clases que capturen la información, en el caso de que se desea desplegar la información.

Para utilizar un procedimiento que realice inserción, modificacion o eliminacion sobre una entidad de una tabla, se debe habilitar en el administrador de propiedades del objeto (Veremos esto más adelante).

Bueno, ahora a picar el código: Como sabemos, la creación de capas debe de ser de forma ascendente, por lo cual picaremos el código de la capa de acceso a datos (Data access label) y luego nos centraremos en la capa de negocios.

Función que capturará la información de usuarios y creará la lista de los mismos:

Primero, en el espacio de clase dalUsuario crearemos una variable de clase que llamaremos dc de la siguiente forma:

dcPruebaDataContext dc = new dcPruebaDataContext();

Con esto tendremos acceso a los objetos y métodos transaccionales que se han creado para realizar las intervenciones en las entidades de la base de datos, para consultar la información de usuario y retornarla, debemos definir la siguiente función.

// metodo que rescata la informacion de todos los usuarios registrados
public List<clsUsuario> funUsuarioObtener() {
// creamos una estructura que contendr la informaci¢n de los todos los registros
List<clsUsuario> lstUsuario = new List<clsUsuario> { };
try {
var usu = from u in dc.lnqUsuarios
orderby u.usuClave, u.usuLogin, u.usuClave, u.usuEstado ascending
select u;
// realizamos la asignaci¢n de datos
if (usu.Count() > 0){
// cargamos la informaci¢n a retornar
foreach (lnqUsuario u in usu){
clsUsuario cls = new clsUsuario();
cls.Codigo = u.usuCodigo;
cls.Login = u.usuLogin;
cls.Password = u.usuClave;
cls.Estado = u.usuEstado;
lstUsuario.Add(cls);
cls = null;
}
}
}
catch (Exception ex){
throw ex;
}
return lstUsuario;
}


Comentemos el código: Como se observa, la función retornará una lista de estructura de la definición de clase que hemos creado, cuando vamos a buscar la información, lo primero que haremos será utilizar la siguiente sentencia para rescatar esta:

var usu = from u in dc.lnqUsuarios
orderby u.usuClave, u.usuLogin, u.usuClave, u.usuEstado ascending
select u;


Lo que hacemos es seleccionar la información de la entidad lnqUsuarios utilizando la variable de objeto dc, ahora pueden observar que estoy ordenando la información para desplegarla. Luego en "u" se carga la inmformación y la asignamos a la variable usu, que es la que utiliza la declarativa var (nuevo tipo de dato definido para linq).
Puede parecerles que este tipo de dato es muy parecido a la declarativa de javascript, el cual permite definir una variable de cualquier tipo y utilizarlo, no se si microsoft ha tomado la misma idea.
Bueno si quisieramos rescatar directamente la información en la variable var usu y no recorrer el resultado para crear una lista, lo que debemos hacer es lo siguiente:

var usu = from u in dc.lnqUsuarios

orderby u.usuClave, u.usuLogin, u.usuClave, u.usuEstado ascending
select new clsUsuario{
Codigo = u.usuCodigo,
Login = u.usuLogin,
Password = u.usuClave,
Estado = u.usuEstado
};

O bien

IEnumerable<clsUsuario> usu = from u in dc.lnqUsuarios
orderby u.usuClave, u.usuLogin, u.usuClave, u.usuEstado ascending
select new clsUsuario{
Codigo = u.usuCodigo,
Login = u.usuLogin,
Password = u.usuClave,
Estado = u.usuEstado
};



Esto automáticamente nos cargará la información en la variable, pero al retornar la información en la función, debemos asegurarnos que ésta este definida como var o como IEnumerable<clsUsuario> respectivamente, es decir:

public var funUsuarioObtener() {}

public IEnumerable<clsUsuario>funUsuarioObtener() {}


El problema de esto o la consideración que se debe tomar es que debes tener la referencia a System.Linq en todas las capas para tratar la variable retornada.
Como mi intención es que aprendan lo más posible se los pongo desarrollado para que ustedes decidan que opción les conviene.
El siguiente paso será realizar el método que me permitirá rescatar la información de un usuario en específico, la cual la presento a continuación:

// metodo que rescata la informacion de un usuario en especifico
public lnqUsuario funUsuarioEspecificoObtener(string usuLogin, string usuClave){
lnqUsuario usuario = null;
try{
var usu = from u in dc.lnqUsuarios
where (u.usuLogin == usuLogin && u.usuClave == usuClave)
select u;
if (usu.Count() > 0)
usuario = usu.First();
}
catch (Exception ex) {
throw ex;
}
return usuario;
}

Ahora si observan, rescatamos la información asociando condiciones en la clausula where, como se observa en el código anterior. Esta información, nos retornará un registro de usuario y, como dijimos, dentro de la estructura de clase lnqUsuario se agrega la estructura y la información del empleado. (Prueben esto, ya lo verán).
Ahora crearemos la función de insertar un nuevo usuario en la tabla de usuarios, para esto crearemos un procedimiento, ya que no necesitamos retornar valor, solo necesitamos controlar y elevar los errores que se presenten, en el caso de que no exista error, la operación se considera como exitosa:

// metodo encargada de crear un nuevo usuario utilizando la definici¢n creada en csharp con linq to sql class
public void prcUsuarioInsertar(int empCodigo, string usuLogin, string usuClave) {
try {
lnqUsuario usuario = new lnqUsuario();
usuario.empCodigo = empCodigo;
usuario.usuLogin = usuLogin;
usuario.usuClave = usuClave;
usuario.usuEstado = 'A';
dc.lnqUsuarios.InsertOnSubmit(usuario);
dc.SubmitChanges();
}
catch (Exception ex) {
throw ex;
}
}

Comentemos el código: Lo primero es reconocer que debemos validar la no existencia de los datos enviados a esta función, para ello lo ideal es consultar la función de búsqueda del usuario específico y verificar que el resultado de la función sea null para hacer cualquier acción de inserción.

bueno en este caso podremos ver que la variable del objeto Data Context dcPrueba que hemos definido, presenta un método llamado "InsertOnSubmit", que se ha creado para cada una de las estructuras de clases de entidades mapeadas, a la cual se le debe pasar un objeto del tipo de la misma clase para realizar la inserción.
Esta acción no se llevará a cabo hasta que no se ejecute el método SubmitChanges del objeto Data Context creado.
Ahora definiremos el método encargado de realizar la modificación de datos de los usuarios, esto se debe hacer de la siguiente forma:

// metodo interno en csharp que permite realizar la modificaci¢n de datos de un registro
public void prcUsuarioModificar(string usuLogin, string usuClave, string usuNewLogin, string usuNewClave) {
try{
// realizamos la b£squeda del usuario para asignar a la variable
var usu = from u in dc.lnqUsuarios
where (u.usuLogin == usuLogin && u.usuClave== usuClave)
select u;
// verificamos que el usuario exista
if (usu.Count() > 0) {
//si existe entones asignamos un objeto para realizar la modificaci¢n
lnqUsuario usuario = dc.lnqUsuarios.Single(u => u.usuCodigo == usu.First().usuCodigo);
// modificamos los datos del registro
usuario.usuLogin = usuNewLogin;
usuario.usuClave = usuNewClave;
// guardamos los cambios
dc.SubmitChanges();
}
}
catch (Exception ex) {
throw ex;
}
}

Comentemos el código:
Si observan, ahora he utilizado una clausula que nos permite rescatar un registro en especifico que cumpla con los criterios definidos, podría también haver usado el método de consulta de usuarios que retornará en una variable de estructura de clase la información del usuario, pero para tener un espectro mayor de posibilidades les muestro este tipo de búsqueda
Bueno, lo que nos queda es eliminar un registro, para ello, como en el método insert o update, tendremos tambien un método creado en en esquema de la estructura de clase que mapea la entidad llamado DeleteOnSubmit, al cual hay que pasarle una estructura del tipo de clase que define la acción con la información del registro que se desea eliminar en la entidad mapeada.
Esto se hace de la siguiente forma:

// metodo encargado de realizar
// la eliminación de un registro
public void prcUsuarioEliminar(string usuLogin, string usuClave) {
try {
// realizamos la b£squeda del usuario
// para asignar a la variable
var usu = from u in dc.lnqUsuarios
where (u.usuLogin == usuLogin && u.usuClave== usuClave)
select u;
// verificamos que el usuario exista
if (usu.Count() > 0) {
// creamos un nuevo objeto con el usuario seleccionado
lnqUsuario usuario = usu.First();
// realizamos la eliminaci¢n del registro a espera de submit
dc.lnqUsuarios.DeleteOnSubmit(usuario);
dc.SubmitChanges();
}
}
catch (Exception ex) {
throw ex;
}
}


Comente el código: En esta acción podemos ver que primero se realiza una búsqueda del usuario deseado según criterios de selección, que permite retornar la información a una estructura de clase, en este caso he realizado una consulta común y he utilizado el método First, para que vean que podemos movernos dentro del resultado de la búsqueda. Este método retorna la información en una estructura de la clase de usuarios, luego realizamos las acciones de eliminación. como se muestra en las ultimas líneas.
NOTA: LINQ también permite transacciones, no las he puesto en este artículo ya que las acciones se realizaban en una sola entidad de una Base de Datos, pero si no están trabajando con SP y desean tener un comportamiento transaccional controlado, esto se puede manejar en la lógica de programación. Como buenos desarrolladores que son, debe tenerse en consideración, los begin transaction y commit transaction que se definen en los SP o las transacciones las manejan en el programa o en los SP.

LinQ to Sql - Bussiness label


LinQ to Sql (Arquitectura de capas):


Como hemos visto, ya tenemos definida la capa de datos, ahora definiremos la capa de negocios, en este ejemplo, la capa de negocios solo se encargará de capturar las solicitudes de la UI y realizar las solicitudes a la capa de datos, específicamente a la clase dalUsuario, para solicitar o realizar las acciones sobre la entidad lnqUsuarios.


Para construir una Capa de negocios, se deben tener de antemano la mayor cantidad de definiciones de acciones que se deben atender desde la UI (Interfaz de Usuario), por lo cual, ya tenemos claro que haremos en la capa de datos y debemos tener más o menos claro cuales serán las solicitudes desde la UI.

Lo primero que haremos será agregar a la solución un nuevo proyecto de bibliotecas de clase que llamaremos CapaNegocio. Si no saben como hacer esto, deben ir a Archivo, Agregar, Nuevo proyecto y desde la ventana de proyectos seleccionar el lenguaje y el tipo de proyecto que crearemos.
Antes de realizar la siguiente acción, vamos a generar el proyecto de biblioteca de clase CapaDato, para ello con el botón derecho del mouse sobre el proyecto, seleccionaremos la opción generar.
A continuación agregaremos una referencia desde el proyecto CapaNegocio al proyecto CapaDato, si vemos en la carpeta bin del proyecto CapaNegocio, veremos una dll llamada CapaDato.
Podemos construir los métodos de esta capa, si lo desean pueden renombrar la clase que se crea por defecto en el proyecto por brlUsuario (brl por bussiness rules label). Como dije en la introducción de este artículo, los nombres de clase se repiten en los distintos niveles, así como los métodos de las mismas, en algunos casos. Para cualquier caso debemos crear esta clase para continuar con el ejemplo.

En el espacio de nombre de la clase definiremos una variable que referenciará a la clase de la capa de datos dalUsuario, de la siguiente forma:

CapaDato.dalUsuario dalUsuario = new CapaDato.dalUsuario();

Como vamos a trabajar con una solución de UI de windows y vamos a capturar los controles que nos envíen en esta capa, lo que haremos será agregar otra referencia al proyecto CapaNegocio, que referenciará al espacio de nombre System.Windows.Forms, con esto podremos definir variables de tipo de controles de objetos.
Ahora si, piquemos código!!!.

Como sabemos, debemos en nuestra interfaz, desplegar la información de los usuarios, para ello vamos a crear una función que captura la información que se envía desde la UI y realizar las acciones pertinentes, como en este ejemplo no pasaremos los controles a la Capa de negocios voy a poner el código y cada desarrollador, segun su CI jejejeje, interpretará cada función.
Bromas a parte veamos las funciones que crearemos para atender las llamadas desde la UI:

En el siguiente método capturamos toda la información de los usuarios que se encuentran definidos, los cuales serán desplegados de alguna forma en la UI, si observan los métodos de las BRL (Bussiness Rules Label) tienen los mismos nombres que en la DAL (Data Access Label)

public List funUsuarioObtener(){
List usuario = null;
try{ usuario = dalUsuario.funUsuarioObtener(); }
catch (Exception ex) { throw ex; }
return usuario;
}

En el siguiente método capturamos la información de un usuario en especifico según los criterios enviados y retorna la información

public CapaDato.lnqUsuario funUsuarioObtener(string usuario, string clave) {
CapaDato.lnqUsuario cls = null;
try { cls = this.dalUsuario.funUsuarioEspecificoObtener(usuario, clave); }
catch (Exception ex){ throw ex; }
return cls;
}

El siguiente método realiza la llamada a la inserción de un registro al método creado en la capa de datos que realizar esta acción utilizando los m‚todos dispuestos en linq to sql

public void prcUsuarioInsertar(int empleado, string usuario, string clave) {
try { this.dalUsuario.prcUsuarioInsertar(empleado, usuario, clave); }
catch (Exception ex) { throw ex; }
}

El siguiente método realiza la llamada a la modificación de un registro al método creado en la capa de datos que realizar esta acción utilizando los m‚todos dispuestos en linq to sql

public void prcUsuarioModificar(string usuario, string clave, string newusuario, string newclave) {
try { this.dalUsuario.prcUsuarioModificar(usuario, clave, newusuario, newclave); }
catch (Exception ex) { throw ex; }
}

El siguiente método realiza la llamada a la eliminación de un registro al m‚todo creado en la capa de datos que realizar esta acción utilizando los m‚todos dispuestos en linq to sql

public void prcUsuarioEliminar(string usuario, string clave) {
try { this.dalUsuario.prcUsuarioEliminar(usuario, clave); }
catch (Exception ex) { throw ex; }
}

Ahora, cada uno puede hacer las cosas como le parezca mejor, yo solo les entrego los lineamientos Base, ya que claramente si depuro este código desde una perspectiva de reuzabilidad, lo puedo mejorar mucho más.
Bueno señores, el siguiente paso es crear la UI y con esto podemos probar lo que hemos hecho, ahunque debo decir, que tal como esta este ejemplo, lo podemos usar para web, como para windows, ya que como no estamos pasando controles de objetos a la capa no esta personzalidada la Capa, más bien esta habierta y se puede reutilizar en más ambientes.

LinQ to Sql - Interface label


LinQ to Sql (Arquitectura de capas):



Bueno si quisieramos terminar este artículo con broche de oro, lo suyo sería que la interfaz la hiciera con WPF, pero como este tema hay que verlo un poco mejor vamos a hacer la UI con una aplicación Windows Forms.
Para ello agregaremos a la solución que construímos un nuevo proyecto del tipo de Windows Forms Application.
El siguiente paso será agregar las referencias a los proyectos de CapaDato y CapaNegocio, debemos entender que el proyecto de capa de dato desde esta solución windows, solo lo usaremos para utilizar la definición de estructuras de clases definidas, en ningún caso haremos una llamada a la clase dalUsuario, ya que estas llamadas se hacen desde la Capa de negocio, así es como se trabaja en capas.


La interfaz que debemos definir debe tener los siguientes controles, la distribución se las dejo a ustedes, yo los he puesto así:



Con los siguientes nombres:

  • dgvUsuario DataGridView
  • lblUsuario Label
  • lblClave Label
  • lblEstado Label
  • lblCodigo Label
  • txtCodigo TextBox
  • txtUsuario TextBox
  • txtClave TextBox
  • txtEstado TextBox
  • btnModificar Button
  • btnEliminar Button
  • btnInsertar Button

Ahora a picar código amigos!!!

Antes que todo, en el espacio de nombre de la clase de formulario, agregaremos la siguiente definición de variable de clase de la capa de negocio


CapaNegocio.brlUsuario brlUsuario = new CapaNegocio.brlUsuario();

1 - En el método que atiende el evento load de la página agregaremos las siguientes líneas de código:


private void frmUsuario_Load(object sender, EventArgs e){
try {
this.dgvUsuario.DataSource = this.brlUsuario.funUsuarioObtener();
}
catch (Exception ex){
MessageBox.Show(ex.Message);
}
}

Lo que hacemos es desplegar la información de los usuarios en el datagridview, en este caso retornamos la lista de estructura de clases y esta automáticamente se despliega.

2 - Ahora definiremos la acción de selecciona de un registro del data grid view para ello, en el método que atiende el evento CellContentClick agregaremos las siguientes líneas de código, en el cual, el método selecciona y desplega la información de un usuario en la sección de modificación eliminación de datos.


private void dgvUsuario_CellContentClick(object sender, DataGridViewCellEventArgs e){
try{
int idx = this.dgvUsuario.CurrentRow.Index;
string usuario = this.dgvUsuario[1,idx].Value.ToString();
string clave = this.dgvUsuario[2,idx].Value.ToString();


CapaDato.lnqUsuario usu = this.brlUsuario.funUsuarioObtener(usuario, clave);

this.txtCodigo.Text = usu.usuCodigo.ToString().Trim();
this.txtUsuario.Text = usu.usuLogin.ToString().Trim();
this.txtClave.Text = usu.usuClave.ToString().Trim();
this.txtEstado.Text = usu.usuEstado.ToString().Trim();

MessageBox.Show(usu.lnqEmpleado.empNombre.ToString() + " " +
usu.lnqEmpleado.empApellidoPrimero.ToString());
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}

En este caso se observa que utilizamos una definición de estructura para capturar la información que se retorna desde la Capa de negocios, como dijimos esta estructura está definida en la capa de datos, pero el acceso a los datos (Transacciones), se realiza desde la capa de negocio.

3 - En el método que atiende el evento click del botón btnInsertar agregaremos las siguientes líneas de código:


private void btnInsertar_Click(object sender, EventArgs e)
{
try
{
string usuario = this.txtUsuario.Text;
string clave = this.txtClave.Text;
int empleado = 1;
this.brlUsuario.prcUsuarioInsertar(empleado, usuario, clave);
this.dgvUsuario.DataSource = this.brlUsuario.funUsuarioObtener();
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}

4 - En el método que atiende el evento click del boton btnModificar agregaremos las siguientes líneas de código:


private void btnModificar_Click(object sender, EventArgs e){
try {
if (this.dgvUsuario.SelectedCells.Count == 0){
throw new Exception("Debe seleccionar una fila");
}
int idx = this.dgvUsuario.CurrentRow.Index;
string usuario = this.dgvUsuario[1, idx].Value.ToString();
string clave = this.dgvUsuario[2, idx].Value.ToString();
string newusuario = this.txtUsuario.Text;
string newclave = this.txtClave.Text;
this.brlUsuario.prcUsuarioModificar(usuario, clave, newusuario, newclave);
this.dgvUsuario.DataSource = this.brlUsuario.funUsuarioObtener();
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}

5 - En el método que atiende el evento click del botón btnEliminar agregaremos las siguientes líneas de código:


private void btnEliminar_Click(object sender, EventArgs e){
try {
if (this.dgvUsuario.SelectedCells.Count == 0) {
throw new Exception("Debe seleccionar una fila");
}
int idx = this.dgvUsuario.CurrentRow.Index;
string usuario = this.dgvUsuario[1, idx].Value.ToString();
string clave = this.dgvUsuario[2, idx].Value.ToString();
this.brlUsuario.prcUsuarioEliminar(usuario, clave);
this.dgvUsuario.DataSource = this.brlUsuario.funUsuarioObtener();
}
catch (Exception ex){
MessageBox.Show(ex.Message);
}
}

Bueno señores. Como resumen, podemos ver que LinQ to SQL cumple con todas las especificaciones para trabajar orientado a objetos. ABAJO CON LAS CREENCIAS DE QUE NO SE PODIA PROGRAMAR A OBJETOS CON LINQ.

Claro esta que si se ven los ejemplos introductorios nunca podremos programar OO, pero con este ejemplo, que es totalmente mejorable, se puede observar que cumple con las Bases de la Programación OO sin problemas.

Bueno señores los dejo y espero que antes de fin de mes pueda agregar la capa de datos ejecutada con procedimientos almacenados "LA LLEVA(expreción de muy bueno en Chile) - MOLA (expreción de muy bueno en España)".

LinQ to Object


LinQ to Sql (Arquitectura de capas):


Ahora vamos a ver el comportamiento funcional de LinQ to Object, este permite realizar cualquier tipo de búsqueda en los tipos de objetos que se manejan en la definición del framework 3.5, podemos realizar acciones de búsqueda sobre arreglos de una o más dimenciones, para rescatar datos en específico o, podemos realizar búsquedas sobre listas, ya que realizaremos modificaciones sobre listas de clases de objetos.

Como vimos, en los ejemplos de LINQ TO SQL, lo que haciamos hera retornar listas que tenían estructuras de clases, ahora lo que haremos, será, tomar estas listas de datos y realizar acciones sobre estas.

Este ejemplo no se conectará a Base de Datos para traer la información, sino más bien, vamos a crear nuestra lista y realizaremos acciones sobre esta, para ello debemos crear la siguiente interfaz:


Los controles los he nombreado de la siguiente forma (ustedes pueden distribuirlos y nombrarlos como quieran):

  • txtNombre TextBox
  • txtApellidoPaterno TextBox
  • txtApellidoMaterno TextBox
  • txtFechaNacimiento TextBox
  • lblNombre Label
  • lblApellidoMaterno Label
  • lblApellidoPaterno Label
  • lblFechaNacimiento Label
  • btnAgregar Button
  • btnBuscar Button
  • Edad Label
  • label2 Label
  • txtEdad TextBox
  • txtNombreBusqueda TextBox
  • lvwPersona ListView
  • btnBusqueda2 Button

Comentemos el ejemplo, bueno, lo que haremos será crear una lista en la cual buscaremos información de una persona según su edad (Este ejemplo está basado en uno de los que Microsoft a lanzado para Visual Basic este año).

Para ello debemos agregar usuarios a la lista, desplegar los mismos y, realizar las búsquedas de estos por el o los criterios definidos, entonces vamos a ello:

primero crearemos en el mismo archivo del formulario, pero fuera del estacio de nombre de clase de formulario, pero dentro del namespace la siguiente clase:


public class clsPersona
{
private string _strNombre;
private string _strApellidoPaterno;
private string _strApellidoMaterno;
private DateTime _fcFechaNacimiento;
public string Nombre{
get { return _strNombre; }
set { _strNombre = value; }
}
public string ApellidoPrimero{
get { return _strApellidoPaterno; }
set { _strApellidoPaterno = value; }
}
public string ApellidoSegundo{
get { return _strApellidoMaterno; }
set { _strApellidoMaterno = value; }
}
public DateTime FechaNacimiento{
get { return _fcFechaNacimiento; }
set { _fcFechaNacimiento = value; }
}
public int Edad{
get{
try{
DateTime iDia = DateTime.Now;
return (int)iDia.Subtract(FechaNacimiento).TotalDays / 365;
}
catch (Exception ex){throw ex;}
}
}
}

Si se observa lo que haremos será utilizar esta estructura para crear una lista, luego realizaremos una búsqueda se personas según su edad y, es aquí en donde la propiedad Edad() se torna importante.

Ahora crearemos dos funciones, las cuales cooperarán para agregar a la lista los nuevos registros de personas.

1 - En el espacio de nombre de la clase del formulario que han creado definiremos la siguiente variable de lista:


List lstPersona = new List { };

2 - En el método que atiende el evento click del botón btnAgregar definiremos las siguientes líneas de código:


private void btnAgregar_Click(object sender, EventArgs e) {
try {

// creamos el nuevo registro y lo agregamos a la lista
clsPersona cls = new clsPersona();
cls.Nombre = this.txtNombre.Text;
cls.ApellidoPrimero = this.txtApellidoPaterno.Text;
cls.ApellidoSegundo = this.txtApellidoMaterno.Text;
cls.FechaNacimiento = DateTime.Parse(this.txtFechaNacimiento.Text);
this.lstPersona.Add(cls);

// desplegamos la información de la lista
this.prcCrearColumna();
string[] reg = new string[4];
int num = this.lstPersona.Count();

for (int i = 0; i <>reg[0] = this.lstPersona[i].Nombre.ToString();
reg[1] = this.lstPersona[i].ApellidoPrimero.ToString() + " " +
this.lstPersona[i].ApellidoSegundo.ToString();
reg[2] = this.lstPersona[i].FechaNacimiento.ToString("dd/MM/yyyy");
reg[3] = this.lstPersona[i].Edad.ToString();

ListViewItem lvi = new ListViewItem(reg);
this.lvwPersona.Items.Add(lvi);
}
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
}

Ahora como estamos trabajando con un listview debemos crear las columnas, para ello y, por que se está llamando desde la función anterior crearemos el siguiente método:

private void prcCrearColumna() {
try {
this.lvwPersona.Clear();
this.lvwPersona.View = View.Details;
this.lvwPersona.Columns.Add("Nombre", 150, HorizontalAlignment.Left);
this.lvwPersona.Columns.Add("Apellidos", 200, HorizontalAlignment.Left);
this.lvwPersona.Columns.Add("Fecha Nacimiento", 200, HorizontalAlignment.Left);
this.lvwPersona.Columns.Add("Edad", 50, HorizontalAlignment.Left);
}
catch (Exception ex) { throw ex; }
}

Bueno, ya tenemos definida la lógica para gregar registros de personas a la lista, ahora lo que debemos hacer es definir el criterio de búsqueda dentro del objeto de lista que hemos creado, para ello y como según definimos en los botones de búsqueda definiremos dos tipos de búsuqueda: simple y formateada.

3 - Busqueda y despliegue de datos de forma simple.

En la búsqueda simple lo que haremos será rescatar la información, según el criterio definido y desplegarlo en pantalla mediante un messagebox, esto se hará en el método que atiende el evento click del boton btnBuscar y, las líneas de código se observan a continuación:


private void btnBuscar_Click(object sender, EventArgs e) {
try {
int edad = (txtEdad.Text != "") ? int.Parse(txtEdad.Text) : 0;
string nombre = (txtNombreBusqueda.Text != "") ? txtNombreBusqueda.Text : "";

var qry = from p in lstPersona
where (p.Edad > edad && p.Nombre.IndexOf(nombre) != -1)
orderby p.Nombre, p.ApellidoPrimero, p.ApellidoSegundo, p.FechaNacimiento, p.Edad
select p;

foreach (var p in qry){
string msg =
string.Format(" Nombre {0}\r\n Fecha de Nacimiento {1}\r\n Edad {2} años",
p.Nombre + " " + p.ApellidoPrimero + " " + p.ApellidoSegundo,
p.FechaNacimiento.ToString("dd/MM/yyyy"), p.Edad);

MessageBox.Show(msg);
}
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
}

Bueno, que más decir, si comentamos el código nos centraremos en la lógica de búsqueda, en la cual se realizará la búsqueda dentro del objeto lstPersona segun nombre y la propiedad edad. La propiedad Edad tomará la fecha y calculará si el usuario cumple con la edad requerida y la coincidencia de nombre entregado.

Vean que cuando busco el nombre utilizo los métodos asociados a la clase string, es decir IndexOf, con esto podemos ver que las sentencias del lenguaje pueden perfectamente ponerse dentro de la clausula where.

Por ultimo, si existen más de un registro en la lista de estructura de clase, debemos desplegarlo, por eso he definido el despliegue en un foreach.

Cuando el tipo de dato no les funciones, lo mejor es asignar el recorrido del foreach a la clausula var

4 - Busqueda y despliegue de datos de forma formateada.

Bueno la direferencia que existe en la búsqueda simple es que sin crear un objeto de clase en el resultado de búsqueda como vimos en LinQ to Sql también podemos crear formatos de resultados abstractos creados en el resultado asignado. Para ver esto, en el método que atiende el evento click del botón btnBusqueda2, agregaremos las siguientes líneas de código:


private void btnBusqueda2_Click(object sender, EventArgs e) {
try {
int edad = (txtEdad.Text != "") ? int.Parse(txtEdad.Text) : 0;
string nombre = (txtNombreBusqueda.Text != "") ? txtNombreBusqueda.Text : "";

var qry = from p in lstPersona
where (p.Edad > edad && p.Nombre.IndexOf(nombre) != -1)
orderby p.Nombre, p.ApellidoPrimero, p.ApellidoSegundo, p.FechaNacimiento
select new {
NombreApellidos = string.Format("{0} {1} {2}",
p.Nombre, p.ApellidoPrimero,
p.ApellidoSegundo),
p.FechaNacimiento,
p.Edad
};

foreach (var p in qry) {
string msg = string.Format(" Nombre {0}\r\n Fecha de Nacimiento {1}\r\n Edad {2} años",
p.NombreApellidos, p.FechaNacimiento.ToString("dd/MM/yyyy"), p.Edad);
MessageBox.Show(msg);
}
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
}

Comentemos el código: si se observa ahora estamos creando el formato de salida del resultado de la búsqueda en las siguientes líneas

var qry = from p in lstPersona
where (p.Edad > edad && p.Nombre.IndexOf(nombre) != -1)
orderby p.Nombre, p.ApellidoPrimero, p.ApellidoSegundo, p.FechaNacimiento
select new {
NombreApellidos =
string.Format("{0} {1} {2}", p.Nombre, p.ApellidoPrimero,p.ApellidoSegundo),
p.FechaNacimiento,
p.Edad };

Ahora la concatenación de datos se hace dentro del resultado, no he probado formatear la fecha, prueben, no deberían tener problemas.

Ahora a probar, suerte y saludos

LinQ to XML


LinQ to Sql (Arquitectura de capas):


LinQ to XML en pocas palabras nos permite leer, definir y escribir datos en estructura XML. Con esto podemos acceder a información desde diferentes canales, como conectarnos a un directorio de archivos y abrir un xml o rescatar un xml entregado desde un servicio web o desde cualquier otro canal que nos entregue un archivo xml.

Bueno si observamos en el ejemplo siguiente podemos rescatar de forma más facil la información de un nodo que con la API de XmlReader/XmlWriter. Una de las ventajas que caracterizan este tipo de objeto es que es más eficiente y usa menos memoria que la API DOM que tiene XmlDocument.

Ahora al ejemplo:

El ejemplo consistirá en capturar un archivo xml y realizar acciones sobre este. Si bien es cierto podemos obtener, como dijimos, un xml de muchas partes, desde un procedimiento almacenado usando un for xml explicit, construyendo uno a raiz de un resultas, rescatando uno desde un WebService, etc.
Nosotros lo que haremos será utilizar el ejemplo que definimos en LinQ to Object para generar nuestro archivo xml y luego vamos a realizar acciones sobre este, en el caso de que no quieran tomar el ejemplo anterior les pongo a dispocición un xml de ejemplo.

<?xml version='1.0'?>
<Datos>
<dato edad='35'>
<nombre>Mario</nombre>
<appPrimero>Roa</appPrimero>
<appSegundo>Vidal</appSegundo>
<fNacimiento>28/09/1972 0:00:00</fNacimiento>
</dato>
<dato edad='37'>
<nombre>Juan</nombre>
<appPrimero>Paco</appPrimero>
<appSegundo>De la Mar</appSegundo>
<fNacimiento>10/11/1970 0:00:00</fNacimiento>
</dato>
<dato edad='32'>
<nombre>Pedro</nombre>
<appPrimero>Manuel</appPrimero>
<appSegundo>Gutierrez</appSegundo>
<fNacimiento>10/12/1975 0:00:00</fNacimiento>
</dato>
</Datos>

Ustedes solo escriben las líneas que necesiten, ya que pueden leer directamente el Xml desde un archivo de directorio, utilizando el objeto XDocument.Load(URL), que se encuentra en el espacio de nombre System.Xml.Linq, por lo cual en la cabecera del archivo de formulario debemos agregar los siguientes espacios de nombre:

using System.Xml.Linq;

Nosotros lo que haremos en este caso será parsear el string del xml a XDocument para poder operar con el, con lo cual, agregaremos un botón a la aplicación para realizar nuestro ejercicio, como se muestra a continuación:

Primero crearemos un método en forma de función que nos retornará el string con el xml que contendrá la información de la lista creada, de la siguiente forma:

string fnXmlObtener() {
string sXml = "";
try{
sXml = "<?xml version='1.0'?>";
sXml += "<Datos>";
for (int i = 0; i < lstPersona.Count; i++)
{
sXml += "<dato edad='" + lstPersona[i].Edad.ToString() + "'>";
sXml += "<nombre> + lstPersona[i].Nombre.ToString() + "</nombre>";
sXml += "<appPrimero>" + lstPersona[i].ApellidoPrimero.ToString() + "</appPrimero>";
sXml += "<appSegundo>" + lstPersona[i].ApellidoSegundo.ToString() + "</appSegundo>";
sXml += "<fNacimiento>" + lstPersona[i].FechaNacimiento.ToString() + "</fNacimiento>";
sXml += "</dato>";
}
sXml += "</Datos>";
}
catch (Exception ex) { throw ex; }
return sXml;
}

Ahora vamos a ponerle la lógica al método que atiende el evento click del botón agregado, al cual he llamado btnXml. En este método vamos a agregar dos tipos de búsqueda: Búsqueda por Atributo y Búsqueda por elemento.
  1. Búsqueda por atributo. Esta permitirá a través del atributo edad rescatar los elementos asociados al nodo dato del xml con el que estamos trabajando.
  2. Búsqueda por elemento. Esta permite a través de un elemento, rescatar la información deseada.
1 - Búsqueda por atributo.
En este caso, se realiza la búsqueda comparando el atributo edad asociado al nodo dato. Asocio el código de llamada al xml si no desearan seguir con el ejercicio:

private void btnXml_Click(object sender, EventArgs e)
{
try
{
string sMsg = "";
string sXml = fnXmlObtener();

// --------------------------------------------------------------------------
// Aqui debería ir la llamada al archivo en un directorio
// XDocument xmlD = XDocument.Load(dirPath);
XDocument xmlD = XDocument.Parse(sXml);
// --------------------------------------------------------------------------

var dato = from d in xmlD.Descendants("dato")
where (d.Attribute("edad").Value == this.txtEdad.Text)
select new
{
nombre = d.Element("nombre").Value, appPrimero = d.Element("appPrimero").Value,
appSegundo = d.Element("appSegundo").Value, fNacimiento = d.Element("fNacimiento").Value
};
foreach (var d in dato){
sMsg = "Nombre: " + d.nombre + " " + d.appPrimero + " " + d.appSegundo + "\r\r" +
"Fecha de nacimiento " + d.fNacimiento + "\r\r";
}
MessageBox.Show(sMsg);

}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}

Comentemos el código: Si se observa en la búsqueda realizamos la llamada al nodo en el que deseamos realizar las consultas, una vez que este este definido, mediante la instrucción Value del XAttribute que deseamos comparar, rescatamos la información de los elementos de los nodos que coinciden.

2 - Búsqueda por elemento.
Esta acción busca directamente en los elementos del nodo, para este caso dato, ya que se lo estamos indicando, cuando encuentra coincidentes los despliega de la misma forma que cuando buscaba por elemento.

private void btnXml_Click(object sender, EventArgs e)
{
try
{
string sMsg = "";
string sXml = fnXmlObtener();

// --------------------------------------------------------------------------
// Aqui debería ir la llamada al archivo en un directorio
// XDocument xmlD = XDocument.Load(dirPath);
XDocument xmlD = XDocument.Parse(sXml);
// --------------------------------------------------------------------------

var dato = from d in xmlD.Descendants("dato")
where (d.Element("nombre").Value.IndexOf(this.txtNombreBusqueda.Text) != -1)
select new
{
nombre = d.Element("nombre").Value, appPrimero = d.Element("appPrimero").Value,
appSegundo = d.Element("appSegundo").Value, fNacimiento = d.Element("fNacimiento").Value
};

foreach (var d in dato){
sMsg = "Nombre: " + d.nombre + " " + d.appPrimero + " " + d.appSegundo + "\r\r" +
"Fecha de nacimiento " + d.fNacimiento + "\r\r";
}
MessageBox.Show(sMsg);
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}

Bueno amigos a probar y espero que todo funcione bien