post icon

Un ejemplo sencillo y entendible de LINQ con C#

Este tema de LINQ produjo su conmoción desde que apareció como herramienta de rápido desarrollo para mapeo ORM, es decir, crear una abstracción de las tablas de nuestra base de datos en clases para nuestra aplicación, una tabla – una clase.

Por ser un concepto relativamente nuevo, no quiere decir que sea complejo implementarlo, al contrario, es más sencillo y veloz el desarrollo de este modo. Personalmente me recuerda cierta tecnología de java. (sólo cierta semejanza ya que su implementación no es igual).

Primeramente para nuestro ejemplo necesitaremos una base de datos de ejemplo, el script lo tienen debajo. Es una BD pequeña con 3 tablas a modo ilustrativo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
CREATE DATABASE LinqUniversidad;
GO
 
USE LinqUniversidad
GO
/****** Object:  Table [dbo].[Maestros]    Script Date: 12/19/2009 09:09:50 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Maestros](
	[IdMaestro] [int] IDENTITY(1,1) NOT NULL,
	[Nombres] [varchar](50) NOT NULL,
	[Documento] [varchar](25) NOT NULL,
	[FechaNacimiento] [datetime] NOT NULL,
 CONSTRAINT [PK_Maestros] PRIMARY KEY CLUSTERED
(
	[IdMaestro] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
/****** Object:  Table [dbo].[Materias]    Script Date: 12/19/2009 09:09:50 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Materias](
	[IdMateria] [int] IDENTITY(1,1) NOT NULL,
	[Nombre] [varchar](50) NOT NULL,
 CONSTRAINT [PK_Materias] PRIMARY KEY CLUSTERED
(
	[IdMateria] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
/****** Object:  Table [dbo].[MateriasMaestros]    Script Date: 12/19/2009 09:09:50 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[MateriasMaestros](
	[IdMateria] [int] NOT NULL,
	[IdMaestro] [int] NOT NULL,
 CONSTRAINT [PK_MateriasMaestros] PRIMARY KEY CLUSTERED
(
	[IdMateria] ASC,
	[IdMaestro] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object:  ForeignKey [FK_MateriasMaestros_Maestros]    Script Date: 12/19/2009 09:09:50 ******/
ALTER TABLE [dbo].[MateriasMaestros]  WITH CHECK ADD  CONSTRAINT [FK_MateriasMaestros_Maestros] FOREIGN KEY([IdMaestro])
REFERENCES [dbo].[Maestros] ([IdMaestro])
GO
ALTER TABLE [dbo].[MateriasMaestros] CHECK CONSTRAINT [FK_MateriasMaestros_Maestros]
GO
/****** Object:  ForeignKey [FK_MateriasMaestros_Materias]    Script Date: 12/19/2009 09:09:50 ******/
ALTER TABLE [dbo].[MateriasMaestros]  WITH CHECK ADD  CONSTRAINT [FK_MateriasMaestros_Materias] FOREIGN KEY([IdMateria])
REFERENCES [dbo].[Materias] ([IdMateria])
GO
ALTER TABLE [dbo].[MateriasMaestros] CHECK CONSTRAINT [FK_MateriasMaestros_Materias]
GO

Ahora necesitamos crear un proyecto nuevo, de tipo Windows Forms con C#, aunque LINQ se puede usar en cualquier otro tipo de proyecto, aquí lo haremos de este modo, debido a su rápida implementación para el ejemplo. Necesitaremos 3 pantallas la cuales se ven aquí..

form1

form2

form3

El siguiente paso es registrar nuestra base de datos en el explorador de servidores del IDE, lo cual doy por sentado es sabido por todos como hacerlo. Apenas terminamos eso debemos agregar al proyecto un elemento nuevo de Clases de LINQ to SQL con este nombre: LinqUniversidad.dbml.

En el último objeto creado arrastramos las 3 tablas desde el explorador de servidores y Visual Studio se encargará de mapear en clases por nosotros. Es recomendado no hacer cambios en éstas clases a no ser que estemos totalmente seguros de lo que estamos haciendo, si deseamos agregar funciones bien podemos hacerlo desde clases externas 😀 (como lo haremos aquí)..

Debería quedar algo así nuestro mapeo gráfico..

mapeo

Ya es hora de agregar la clase LINQ, la cual llamaremos LinqMaestros.cs, su contenido será el siguiente y se encargará de tener los métodos de creación y búsquedas de maestros..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace SysUniversidad
{
    class LinqMaestros
    {
 
        LinqUniversidadDataContext univ = new LinqUniversidadDataContext();
 
        // metodo para crear un registro de maestro
        internal int CrearMaestro(string nombres, string documento, DateTime fechaNacimiento)
        {
            // instancia de maestro
            Maestros maestro = new Maestros();
 
            // asignacion de atributos
            maestro.Nombres = nombres;
            maestro.Documento = documento;
            maestro.FechaNacimiento = fechaNacimiento;
 
            // preparamos el objeto a insertar
            univ.Maestros.InsertOnSubmit(maestro);
 
            try
            {
                // confirmamos la creacion
                univ.SubmitChanges();
                // retornamos el valor del identity
                return maestro.IdMaestro;
            }
            catch (Exception ex)
            { throw ex; }
        } // end Crear Maestro
 
        // metodo para buscar un maestro por su ID
        internal Maestros BuscarMaestroById(int idMaestro)
        {
            try
            {
                // query linq para obtener un maestro
                var maestro = from m in univ.Maestros
                              where m.IdMaestro == idMaestro
                              select m;
 
                // verificar si existia lo buscado
                if (maestro.Count() > 0)
                    return maestro.First();
                else
                    return null;
            } catch (Exception ex) {
                throw ex;
            } // end try
        } // end BuscarMaestroById
 
        // metodo para listar todos los maestros
        internal IEnumerable BuscarMaestros()
        {
            try
            {
                // query linq para obtener la lista de maestros
                 return from m in univ.Maestros
                              select m;
 
            } catch (Exception ex) {
                throw ex;
            } // end try
        } // end BuscarMaestroById
    } // end LinqDeploy
} // end SysUniversidad

La pantalla principal contendría este código, viéndose los métodos de los botones..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
 
namespace SysUniversidad
{
    public partial class frmMaestros : Form
    {
        public frmMaestros()
        {
            InitializeComponent();
        }
 
        private void btnGuardar_Click(object sender, EventArgs e)
        {
            // procedemos a guardar
            LinqMaestros qMaestro = new LinqMaestros();
            int identity;
            try
            {
                identity = qMaestro.CrearMaestro(txtNombres.Text, txtDocumento.Text, dtpFecha.Value);
                MessageBox.Show("Se ha creado el Maestro: " + txtNombres.Text + " Con Identificador: " + identity);
            } catch (Exception ex) {
                MessageBox.Show(ex.Message);
            } // end try
        } // end btnGuardar_Click
 
        void CargarPantalla(Maestros maestro)
        {
            if (maestro == null)
            { // limpiamos pantalla
                txtNombres.Text = String.Empty;
                txtDocumento.Text = String.Empty;
                dtpFecha.Value = DateTime.Now;
            } else { // cargamos la pantalla
                txtNombres.Text = maestro.Nombres;
                txtDocumento.Text = maestro.Documento;
                dtpFecha.Value = maestro.FechaNacimiento;
            } // endif
        } // end CargarPantalla
 
        private void btnBuscar_Click(object sender, EventArgs e)
        {
            // instanciamos el linq y el form
            LinqMaestros qMaestros = new LinqMaestros();
            frmBuscarMaestro buscar = new frmBuscarMaestro();
            buscar.ShowDialog();
            try {
                // hacemos peticion del retorno de lo ingresado en la pantalla de buscar
                Maestros maestro = qMaestros.BuscarMaestroById(buscar.DevolverId);
                CargarPantalla(maestro);
            } catch (Exception ex) {
                MessageBox.Show(ex.Message);
            } // end try
        } // end btnBuscar_Click
 
        private void btnListarMaestros_Click(object sender, EventArgs e)
        {
            frmListaMaestros Lista = new frmListaMaestros();
            LinqMaestros qMaestros = new LinqMaestros();
            try {
                // asignamos al datasource de la grilla la lista de maestros recuperada
                Lista.dtpListaMaestros.DataSource = qMaestros.BuscarMaestros();
                Lista.ShowDialog();
            } catch (Exception ex) {
                MessageBox.Show(ex.Message);
            } // end try
        } // end btnListarMaestros_Click
    } // end class
} // end namespace

Y por último tan solo quedaría el código de la pantalla de búsqueda, el formulario para listar no contendrá código alguno..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
 
namespace SysUniversidad
{
    public partial class frmBuscarMaestro : Form
    {
        public frmBuscarMaestro()
        {
            InitializeComponent();
        }
 
        private void cmdBuscar_Click(object sender, EventArgs e)
        {
            this.Close();
        }
 
        public int DevolverId
        {
            get
            {
                int i = 0;
                int.TryParse(txtId.Text, out i);
                return i;
            } // end get
        } // end DevolverId
    }
}

Nota: Debemos recordar modificar el modificador de la grilla en el formulario frmListarMaestros a public

19 Diciembre 2009

Comentarios desde Facebook:

  1. avatar
    pepinocom MEXICO Google Chrome Windows
    29 Mayo 2014 at 18:31 #

    aevr que pepsi como le hiciste

  2. avatar
    FoxNew PERU Google Chrome Windows
    5 Septiembre 2013 at 13:20 #

    estoy utlizando Visual 2012, hay solo dos cosas que corregi o q no corren en la version:
    if (maestro.Count() >= 1 )
    return maestro.First();
    else
    return null;

    y agregar: using System.Collections;

    muchas gracias x el ejemplo 🙂

  3. avatar
    Mary CANADA Mozilla Firefox Windows
    13 Marzo 2013 at 03:21 #

    Yo soy nueva en esto y este ejemplo me da la esperanza de aprender lo que mi profe no me ha ensenado bien. Pero me da un error, no encuentra Maestros
    que es Maestros, una classe generada desde la BD o una clase que yo debo crear?

    void CargarPantalla(Maestros maestro)
    internal Maestros BuscarMaestroById(int idMaestro)

    Gracias

    • avatar
      Apolinar Maldonado Internet Explorer Windows
      7 Agosto 2013 at 20:21 #

      Da una infinidad de errores el código, pero con un poco de colmillo y conocimiento se logra echar a andar. Escribeme a i_ams_i@hotmail.com y yo te envío mi proyecto que ya funciona. =)

    • avatar
      Juba MEXICO Google Chrome Windows
      20 Diciembre 2013 at 13:06 #

      Maestro debe ser una clase que tu creas

  4. avatar
    spawn3000 Mozilla Firefox Windows
    22 Septiembre 2012 at 19:29 #

    Se debe tener en cuenta que este concepto “mapear” existe hace mucho tiempo en Java y solo es uno mas de sus intentos de imitarlo… Pero son igual de eficientes?? Esa es la cuestion!!

  5. avatar
    javiersinho COSTA RICA Google Chrome Windows
    30 Noviembre 2011 at 17:28 #

    hola no se me generan las clases que dices ahi mando las tablas al server explorer lo guardo y nada

  6. avatar
    javiersinho COSTA RICA Google Chrome Windows
    30 Noviembre 2011 at 17:27 #

    hola viera que a la hora que paso las tablas con server explorer no se me genera las clase que dices ahi que tengo que hacer

  7. avatar
    GeekZero PARAGUAY Google Chrome Windows
    11 Agosto 2010 at 16:13 #

    Hola Ninoska, que bueno que lo estes comprendiendo. Lo que has visto aquí implementado es una parte muy básica de la OPP, puedes verlo aplicado de un modo más fuerte aqui: http://www.devtroce.com/2010/07/12/como-programar

    Son capas construidas con C#, y puedes usarlo en Desktop como en Web, la guía esta partida en 5 partes, confío en que puedes encontrar las otras 4.

  8. avatar
    Ninoska VENEZUELA Internet Explorer Windows
    11 Agosto 2010 at 15:15 #

    Hola gracias por el aporte fue genial, por fin comprendi lo que es programacion orientada a objetos podrias hacer un ejemplo con programacion orientada a objetos pero aplicacion web. Gracias uso # con Silverlight

  9. avatar
    Marcelo CHILE Google Chrome Windows
    22 Julio 2010 at 02:03 #

    GeekZero, cuando dice "Esto lo digo, porque en sistema que he tocado, ejecutamos querys complejos en la App, y tardaba casi 6 horas en ejecutarse, cuando lo movimos a un Stored Procedure, no tardaba mas de 30 minutos", Linq te permite mapear como métodos los Store Procedure para utilizarlos fácilmente haciendo la conversión correcta en el paso de parámetros (solo arrastrando los SP a la ventana derecha del archivo .dbml).

    • avatar
      GeekZero PARAGUAY Google Chrome Windows
      22 Julio 2010 at 03:47 #

      Hola Marcelo, tienes toda la razon. Simplemente he sido prejuicioso y juezgue mal. Luego de los comentarios @DebianZeus, volvi a probar hacer aplicaciones con Linq, y me di cuenta de eso, es más flexible de lo que parece.

      Lo más seguro que es tan o más potente que como lo cuentan, a pesar de eso tiene una caracteristica que no me gusta (pero es demasiado personal y no pasa por la herramienta en sí) Para mi gusto Linq prácticamente se vuelve un RAD y no me gusta éste sistema sistema de programación simplemente porque no me produce satisfacción, es cierto lo uso laboralmente porque desarrollo con Delphi en Code Gear RAD Studio también, pero como decía no me llena. Estoy muy acostumbrado a programar de este modo:
      http://www.devtroce.com/2010/07/12/como-programar
      Recalco de nuevo, es meramente un gusto personal y probablemente costumbre, a pesar de eso me he propuesto implementarlo en la siguiente aplicación que necesite hacer en el trabajo siempre y cuando sea una App pequeña para afianzarme con Linq.

  10. avatar
    GeekZero Google Chrome Windows
    16 Junio 2010 at 14:59 #

    Hola DebianZeus, excelente que tengas un punto de vista distinto. Por mi parte vale mencionar que no he dicho que LinQ es mala herramienta, sino las herramientas de desarrollo rápido no lo suelen ser, porque pierden mucha flexibilidad, ejemplo Delphi si se trabaja con técnicas RAD, Genexus, etc.

    Soy reacio a este tipo de tecnologías para sistemas grandes, no tanto así para sistemas pequeños e incluso medianos. Los querys en la aplicación en vez de tenerlos en las bases de datos, mas si se tienen estructuras complejas, reglas de negocios que lo complican más y una alta concurrencia de usuarios, tienden a tener un rendimiento pésimo, ya que la BD tiene que verificar la sintaxis del query que es enviada por la App, compilarlo, y ejecutarlo. Además que al no estar almacenado, no crea estadísticas de uso y mucho menos optimizaciones de ejecución. Esto lo digo, porque en sistema que he tocado, ejecutamos querys complejos en la App, y tardaba casi 6 horas en ejecutarse, cuando lo movimos a un Stored Procedure, no tardaba mas de 30 minutos.

    De hecho, tiene varios lados positivos, si uno desarrolla más rápido un sistema, significa mayores ganancias. También es otra ventaja que para conectarse a distintas fuentes, la sintaxis es prácticamente la misma. Y es mucho más fácil de aprender que la programación tradicional, lo cual nuevamente se traduce en mayores ganancias, por lo general.

    En conclusión, no descarto ni desaconsejo su uso, sino más bien, saber elegir una tecnología u otra, según las variables del contexto con el cual se trabajará.

  11. avatar
    DebianZeus PARAGUAY Mozilla Firefox Windows
    16 Junio 2010 at 13:44 #

    Temo divergir con uds. muchachos, en realidad si se tiene un alto control pues cuando uno hace algo como:

    var maestro = from m in univ.Maestros

    where m.IdMaestro == idMaestro

    select m;

    en realidad se traduce a (suponga idMaestro vale 10)

    SELECT * FROM dbo.Maestros WHERE IdMaestro = 10

    se tiene control completo de los verbos con la clase IQueryable todos los where, order by que le digas al linq se traduciran de forma inteligente y optimizada.

    Si aun asi no confias en lo que LINQ traduzca de tu codigo podes tomar control completo encapsulando la programacion en tu DBMS, con vistas y stored procedures, los cuales puede mapear con esta herramienta y llamarlos cual metodos simples se trataran.

    Confien mas en LINQ, es una herramienta muy poderosa y un estandarte digno para el ASP.NET MVC por esto.

    Un saludo 🙂

  12. avatar
    GeekZero PARAGUAY Google Chrome Windows
    12 Febrero 2010 at 10:33 #

    Básicamente tienen la misma temática, pero si mal no recuerdo JPQL solo hace el mapeo ORM contra Bases de Datos, en cambio LINQ se puede conectar a cualquier fuente de datos, ya sean Base de Datos, planillas electrónicas, XML, WS, ficheros planos y otras cosas mas…

    Así como decís, se pierde cierto "control" al utilizar estas tecnologías, por lo que no me inclino mucho a su uso, a no ser que se requiera de un desarrollo muy rápido (lo cual nunca suele llevar a productos de calidad).

    En fin, a mas de uno le servira..

    • avatar
      nio Mozilla Firefox Windows
      16 Enero 2011 at 21:32 #

      hola GeekZero, te quisiera felicitar por el post muy bueno y se entiende re bien todo lo que haces , pero te cuento que no me funciona, no exactamente el tuyo sino con una base d datos que ya tenia y con un pequenio ejemplo que hice enbase al tuyo, mi problema es al insertar en una tabla llamamos al metodo InsertOnSubmit, esto actualiza el contexto de Datos sip y muchas veces, si lo hago correr varias veces, pero no lo inserta en la base de datos real, y si deberia hacerlo al llamar al metodo SubmitChanges();, pero no me funciona :'(, no se que puede estar mal o si es un error comun, o de concepto
      porfa una ayudita con este tema

      • avatar
        GeekZero PARAGUAY Google Chrome Windows
        16 Enero 2011 at 21:52 #

        Hola nio, y que errores te aparecen? simplemente no sucede nada? Trata de subir tu app para verla..

  13. avatar
    pg_shadow PARAGUAY Google Chrome Windows
    12 Febrero 2010 at 09:23 #

    muy bueno el tutorial,  LINQ seria como una especia de JPQL de java, en realidad no me parece sustituir a la verdadera programacion por esto ni por JPQL, es que casi no tenes control sobre lo que se esta haciendo, (insert, update, delete,select), pero tambien hay que ver el lado positivo, es casi magico, yo usaria para formularios simples, o tablas de tipo ABMC y nada mas.

     

    saludos

Trackbacks/Pingbacks

  1. LINQ con C# en .Net. Ejemplos para descargar | puntopeek GERMANY WordPress - 7 Septiembre 2011

    […] de Trucos de LINQ to SQL Ejemplo práctico con LINQ y C# Tutorial de LINQ to SQL […]

Responder