En este articulo vamos a intentar explicar como funciona Linq To SQL. Para empezar diremos que Linq To Sql es un ORM ligero para bases de datos, con soporte para Linq integrado, disponible en la nueva versión de .NET framework.

Para quienes no sepan que es un ORM diremos que es un mapeo entre objetos de bases de datos y objetos de un lengunaje de programación, en nuestro caso serán clases de C#. Es decir, a cada objeto de la base de datos le corresponde un objeto (Clase) de C#.

Lo primero que vamos a necesitar para desarrollar nuestro ejemplo es una pequeña base de datos de SQL Server 2005, que crearemos ejecutando el siguiente script.


CREATE DATABASE LINQDB GO USE LINQDB GO if exists ( select 1 from sysobjects where id = object_id('Perfiles') and type = 'U' ) drop table Perfiles go if exists ( select 1 from sysobjects where id = object_id('Usuarios') and type = 'U' ) drop table Usuarios go if exists ( select 1 from sysobjects where id = object_id('UsuariosPerfiles') and type = 'U' ) drop table UsuariosPerfiles go /*==============================================================*/ /* Table: Perfiles */ /*==============================================================*/ create table Perfiles ( CodPerfil int identity, Perfil varchar(100) not null, Activo char(1) not null constraint CKC_ACTIVO_PERFILES check (Activo in ('S','N')), constraint PK_PERFILES primary key (CodPerfil) ) go /*==============================================================*/ /* Table: Usuarios */ /*==============================================================*/ create table Usuarios ( CodUsuario int identity, Usuario varchar(255) not null, Clave varchar(255) not null, FxAlta datetime not null, Activo char(1) not null constraint CKC_ACTIVO_USUARIOS check (Activo in ('S','N')), constraint PK_USUARIOS primary key (CodUsuario) ) go /*==============================================================*/ /* Table: UsuariosPerfiles */ /*==============================================================*/ create table UsuariosPerfiles ( CodUsuario int not null, CodPerfil int not null, constraint PK_USUARIOSPERFILES primary key (CodUsuario, CodPerfil) ) go alter table UsuariosPerfiles add constraint FK_USUARIOS_REFERENCE_USUARIOS foreign key (CodUsuario) references Usuarios (CodUsuario) go alter table UsuariosPerfiles add constraint FK_USUARIOS_REFERENCE_PERFILES foreign key (CodPerfil) references Perfiles (CodPerfil) go

La base de datos es muy sencilla y contiene solo tres tablas:

  • Usuarios – Que contiene la lista de usuarios.
  • Perfiles – Que contiene la lista de perfiles.
  • UsuariosPerfiles – Que define los perfiles asignados a cada usuario.

En realidad en el articulo solo utilizaremos la tabla de usuarios, pero incluimos tres para demostrar como el asistente de Visual Studio genera multiples clases con Linq To Sql.

Abrimos nuestro Visual Studio 2008 y creamos un nuevo proyecto de tipo Win Forms – es solo la elección que yo he hecho, pero podemos usar Linq To Sql en cualquier proyecto!.

En primer lugar, seleccionamos añadir nuevo elemento y seleccionamos Linq To Sql Classes, llamaremos al archivo LinqDb.dbml.


Con esta acción debemos tener tres nuevos archivos en el proyecto.

  • LinqDb.dbml – es archivo xml que define el mapeo.
  • LinqDb.dbml.layout – es un archivo xml que utiliza el diseñador.
  • LinqDb.designer.cs. – archivo de C# donde se definen las clases y el contexto (la conexión).


Lo siguiente que debemos hacer es definir una conexión a nuestra base de datos. Abrimos el explorador de servidores y añadimos una nueva conexión.


Probamos la conexión y guardamos.

Lo siguiente que vamos a hacer es generar las clases de mapeo con la base de datos. En el explorador del proyecto hacemos doble click en el archivo Linqdb.dbml – con lo que Visual Studio abrirá el diseñador gráfico.

En la ventana del explorador de servidores, seleccionamos la base de datos que hemos creado al inicio del articulo y desplegamos las tablas.

Seleccionamos las tablas que queramos mapear a C# y arrastramos sobre el diseñador. Al arrastrar generamos la clases de mapeo – clases que representan los objetos de base de datos.


Visula Studio nos preguntará si queremos almacenar la información de la conexión a la base de datos en el archivo de configuración de la aplicación.

Una vez hecho esto, podemos examinar el visor de clases, y veremos que se han añadido las siguientes clases a nuestro proyecto:

  • Una clase DataContext – Que representa el contexto de la conexión.
  • Una clase por cada tabla que hayamos seleccionado. Cada clase tendrá una propiedad por cada campo de la tabla a la que representa.


En nuestro proyecto se han creado las siguientes clases:

  • LinqDbDataContext
  • Usuarios
  • Perfiles
  • UsuariosPerfiles

La explicación de estas clases la abordaremos es futuros articulos, pero es importante destacar que si queremos hacer algún cambio en las clase generadas debemos hacerlo en un archivo aparte, aprobechando que son clases parciales. De esta forma podremos regenerar el ORM en cualquier momento sin afectar a nuestro código.

De momento, Visual Studio ha realizado todo el trabajo por nosostros.

Con todo esto añadimos un formulario a nuestro proyecto, en el colocamos tres campos para grabar datos en la tabla de usuarios – el nombre de usuario, la clave de acceso y la fecha de alta.


Escribimos la siguiente clase LinqTest, que dará de alta y buscará usuarios. Tiene los siguientes métodos:

  • AddUsuario – que dará de alta un usuario en la base de datos
  • QueryUsuarioByCodigo – que utilizará Linq para recuperar los datos de un usuario.
partial class LinqTest

{

	LinqDbDataContext dc = new LinqDbDataContext();

	const char SI = 'S';

	internal void AddUsuario(string nombre, string clave, 

				 DateTime fecha)

	{

		Usuarios usuario = new Usuarios();

		usuario.Usuario1 = nombre;

		usuario.Clave = clave;

		usuario.Activo = SI;

		usuario.FxAlta = fecha;

		dc.Usuarios.InsertOnSubmit(usuario);

		dc.SubmitChanges();

		//Probamos si recupera bien los identitys

		MessageBox.Show(

			String.Format("Se ha dado de alta el usuario {0}
					con el código {1}", 

			nombre, 

			usuario.CodUsuario.ToString())

				);

	}

	internal Usuarios QueryUsuarioByCodigo(int codigo)

	{

		var usu = from u in dc.Usuarios

			  where u.CodUsuario == codigo

			  select u;

		if (usu.Count() > 0)

			return usu.First();

		else

			return null;

	}

}

Y ahora el código del formulario para consumir la clase, también muy sencillo:

public partial class Form1 : Form

{

	public Form1()

	{

		InitializeComponent();

	}

 

	private void cmdAlta_Click(object sender, EventArgs e)

	{

	// Damos de alta el registro e inicializamos

		LinqTest obj = new LinqTest();

		obj.AddUsuario( txtUsuario.Text , 

				txtClave.Text, 

				dtpFxAlta.Value);

		PonerDatosEnPantalla(null);

	}

 

	private void cmdBuscar_Click(object sender, EventArgs e)

	{

	// Buscamos y ponemos los datos en pantalla.

		LinqTest obj = new LinqTest();

		frmBuscar f = new frmBuscar();

		f.ShowDialog();

		int codUsuario = f.ReturnValue;

		Usuarios u = obj.QueryUsuarioByCodigo(codUsuario);

		PonerDatosEnPantalla(u);

	}

 

	void PonerDatosEnPantalla(Usuarios u)

	{

		if (u != null)

		{ // Ponemos los datos

			txtUsuario.Text = u.Usuario1;

			txtClave.Text = u.Clave;

			dtpFxAlta.Value = u.FxAlta;

		}

		else

		{ // Inicializamos el formulario

			txtUsuario.Text = String.Empty ;

			txtClave.Text = String.Empty;

			dtpFxAlta.Value = DateTime.Now;

		}

	}

}

El código es muy sencillo, pero lo explicamos brevemente:

  • Boton de alta (cmdAlta_Click) – crea una instancia de LinqTest y le pasa los valores del formulario para que dé de alta un registro.
  • Botón de búsqueda (cmdBuscar_Click) – pide al usuario un código y utilizando una instancia de LinqTest consulta los datos para mostrarlos en pantalla.

Como podemos ver el código se ayuda un formulario de busqueda, tambien muy sencillo.


Por si alguien quiere el código del formulario de busqueda …

public partial class frmBuscar : Form

{

	public frmBuscar()

	{

		InitializeComponent();

	}

 

	private void cmdBuscar_Click(object sender, EventArgs e)

	{

		this.Close();

	}

 

	public int ReturnValue 

	{

		get {	int i = 0;

			int.TryParse(txtCodigo.Text,out i);

			return i; 

			}

	}

}

Pues bien, con esto terminamos. Saludos y hasta la proxima. DJK.