LINQ to SQL

LINQ to SQL (IV): Modificación de datos


Antes de la aparición de LINQ, la filosofía de ADO.NET estaba orientada a datos. De este modo, cuando era necesario modificar o eliminar un registro, nuestro afán era detectar la clave primaria de ese elemento y generar, bien de forma estática, bien de forma dinámica, una sentencia UPDATE o DELETE para que la fuente de datos realizase la operación pertinente sobre ella.

La aparición de los mappers objeto-relacionales como LINQ to SQL intentan hacer algo difícil: desterrar ese concepto de nuestra cabeza y obligarnos a pensar exclusivamente en objetos.

Esta diferencia, al implicar un cambio de paradigma, puede resultar duro. Para ilustrar la diferencia entre ADO.NET básico y LINQ to SQL, veamos un ejemplo.

Anteriormente podíamos usar un DataAdapter para mapear una tabla de base de datos dentro de un DataTable. Y era posible, a partir de ese DataAdapter, obtener dos copias de un mismo conjunto de datos, es decir:


            //Obtenemos la cadena de conexión de App.config o Web.config
            string cadenaConexion = ConfigurationManager.ConnectionStrings["TestDb"].ConnectionString;

            // Creamos una conexión a partir de la cadena de conexión
            using (SqlConnection conexion = new SqlConnection(cadenaConexion))
            {
                // Declaramos una consulta
                string sqlSelect = "select * from Cliente";

                // Abrimos la conexión y generamos un SqlCommand con la conexión y la consulta
                // Instanciamos un SqlDataAdapter a partir del SqlCommand
                conexion.Open();
                SqlCommand commandSelect = new SqlCommand(sqlSelect, conexion);
                SqlDataAdapter dataAdapter = new SqlDataAdapter(commandSelect);

                //Declaramos dos DataTables y los rellenamos con el DataAdapter
                DataTable dt1 = new DataTable();
                DataTable dt2 = new DataTable();

                dataAdapter.Fill(dt1);
                dataAdapter.Fill(dt2);

                conexion.Close();
            }

(más…)

LINQ to SQL (III): Consultas compiladas, ejecución SQL y procedimientos almacenados


Compilación de consultas

En ocasiones podemos encontrarnos con consultas LINQ cuyo coste computacional puede ser alto, haciendo que el sistema se sobrecargue. LINQ to SQL proporciona algunas herramientas que mitigan, dentro de lo posible, el impacto de este tipo de operaciones sobre el rendimiento. Una de ellas es la compilación de consultas.

Es posible precompilar una consulta LINQ, de modo que durante su primera invocación realice un plan de ejecución que pueda mantenerse cacheado para ser reutilizado posteriormente. Así, la siguiente consulta:


            int idCliente = 2;

            var consulta = (from cliente in dbContext.Cliente
                            where (cliente.IdCliente == idCliente)
                            select cliente).FirstOrDefault();

Podría ser compilada y almacenada en una variable, que podrá ser reutilizada posteriormente como si fuese un método normal y corriente. Vemos, además, que la consulta puede parametrizarse, de modo que es posible asignarle cierto grado de generalización.


            var getClientePorId = CompiledQuery.Compile(
                (Testdb contexto, int id) =>
                    (from cliente in contexto.Cliente
                     where (cliente.IdCliente == id)
                     select cliente).FirstOrDefault()
                );

(más…)

LINQ to SQL (II): Relaciones


Ahora que ya sabemos cómo mapear una base de datos relacional en un conjunto de objetos, es momento de profundizar en algunos conceptos y procesos relacionados con esta transformación. El primero de ellos tiene que ver con la forma de tratar las relaciones entre las tablas.

Generalmente, una relación entre dos tablas se establece a través de un campo de la clase que referencia, al que denominamos clave foránea, que “apunta” (toma el valor) de la clave primaria (que identifica cada registro de forma única) de otra tabla.

Así, en el siguiente esquema, el campo IdCliente identifica de forma única a cada cliente, mientras que el campo IdPedido hace lo propio con cada pedido. Sin embargo, la tabla Pedido posee también un campo IdCliente, cuyo valor coincidirá con el campo IdCliente de la tabla Cliente perteneciente al registro que quiere referenciar.

Es decir. Si tenemos los siguientes registros:

Vemos que el campo IdCliente de la tabla Pedido “referencia” al campo IdCliente de la tabla Cliente indicando cuál es el cliente que ha realizado el pedido. A través de operaciones como joins, es posible, a partir del Id del cliente almacenado en el pedido, recuperar los datos del cliente, como su nombre o fecha de nacimiento.

(más…)

LINQ to SQL (I): Mapeo Objeto-Relacional


A estas alturas ya debemos de tener una idea bastante precisa del funcionamiento básico de LINQ. Hemos visto cómo lanzar consultas a listados de objetos (LINQ to Objects) e incluso algún ejemplo sobre cómo iterar sobre ficheros XML (LINQ to XML). Todas estas operaciones tienen un factor común: se realizaban sobre listados que implementaban la interfaz IEnumerable.

Además de poder lanzar consultas sobre listados de objetos, LINQ nos permite una opción aún más potente: lanzar consultas sobre bases de datos SQL Server mediante LINQ to SQL, que no es más que un mapper objeto-relacional, es decir, encargado de transformar sentencias LINQ en expresiones T-SQL y viceversa.

La potencia de LINQ to SQL radica en que, además de permitir realizar operaciones de consulta sobre una base de datos, también es posible realizar inserciones, actualizaciones y eliminaciones de forma nativa. A continuación veremos cómo realizar esto.

La principal desventaja de usar LINQ to SQL es que nuestra base de datos ha de ser, obligatoriamente, SQL Server (no obstante, existen proveedores LINQ para otras bases de datos, como LINQ to Oracle o LINQ to MySQL (vía NuGet). En caso de que todo esto falle y que necesitemos un proveedor personalizado, siempre podremos desarrollar por cuenta propia nuestro propio proveedor. En cualquier caso, siempre podremos utilizar un mapper objeto-relacional más genérico, como por ejemplo Entity Framework, del que hablaremos en posteriores artículos.

En este primer acercamiento a LINQ to SQL hablaremos de cómo establecer la relación entre nuestro programa (orientado a objetos) y nuestra base de datos (relacional). Para ello disponemos de varias posibilidades, que mostraremos a continuación:

(más…)