Hoy en día la mayor parte de las aplicaciones se desarrollan para que accedan a los datos de las bases interactuando con los mismos ya que se encuentran representados en un formato relacional (modelo relacional). Entity Framework nos permite trabajar con datos en forma de objetos y propiedades específicas del dominio sin tener que pensar en las tablas de las bases de datos o columnas en las que se almacenan estos datos. LINQ (Language-Integrated Query) nos facilita la vida a la hora de formular consultas en el código de las aplicaciones para interactuar con la base de datos, sin tener que usar un lenguaje de consulta independiente. A través de la infraestructura de Entity Framework, ADO.NET muestra una vista conceptual común de los datos, como objetos del entorno .NET. Esto hace que la capa de datos sea compatible con LINQ. Esta tecnología, LINQ (LINQ to Entities), nos permite escribir consultas flexibles mediante el uso de operadores de consulta estándar y de expresiones LINQ en el entorno de desarrollo. Las consultas se expresan en el propio lenguaje de programación y no como literales de consulta incrustados en el código permitiendo que el compilador detecte errores de sintaxis en tiempo de compilación.
Una operación de consulta LINQ consta de tres acciones: obtener el origen o los orígenes de datos, crear la consulta y luego ejecutarla. Las instancias de la clase ObjectQuery, que implementa la interfaz genérica IQueryable, actúan como origen de datos para las consultas LINQ to Entities. La clase ObjectQuery genérica representa una consulta que devuelve una instancia o colección de entidades tipadas. Primero debemos crear una instancia de ObjectContext, que es la clase principal para interactuar con un Entity Data Model (EDM) como objetos de CLR (Common Language Runtime). Luego en la consulta especificamos exactamente la información que deseamos recuperar del origen de datos. Una vez creada se debe ejecutar.
Las consultas de LINQ to Entities se pueden formular en dos sintaxis diferentes:
- Sintaxis de expresiones de consulta
- Sintaxis de consultas basadas en métodos
La sintaxis de expresiones de consulta consta de un conjunto de cláusulas escritas en una sintaxis declarativa similar a Transact-SQL. Al usar la sintaxis de consulta, se pueden realizar operaciones complejas de filtrado, clasificación y agrupación en orígenes de datos con una cantidad mínima de código. En el siguiente ejemplo se muestra la operación de consulta completa que incluye la creación de un origen de datos, la definición de la expresión de consulta y la ejecución de la consulta en una instrucción forech:
class LINQQueryExpressions
{
static void Main()
{
// Especificar origen de datos.
int[] numeros = new int[] { 97, 92, 81, 60 };
// Definir la consulta mediante la sintaxis de expresiones.
IEnumerable<int> listaNumeros =
from nro in numeros
where nro > 80
select nro;
// Ejecutar la consulta.
foreach (int i in listaNumeros)
{
Console.Write(i + " ");
}
}
}
// Salida: 97 92 81
Todas las variables utilizadas con este tipo de sintaxis tienen establecimiento inflexible de tipos, aunque no es necesario que proporcionemos el tipo explícitamente ya que el compilador puede deducirlo. Debido a que .NET CLR no reconoce la sintaxis de expresiones de consulta por sí mismo, en tiempo de compilación las expresiones de consulta se convierten en elementos que CLR reconoce: las llamadas a métodos. Estos métodos se conocen como operadores de consulta estándar y tienen nombres como Where, Select, GroupBy, Join, Max, Average, etc. Este tipo de sintaxis no es más que una secuencia de llamadas directas a los métodos de operador de LINQ a las que le debemos pasar como parámetros expresiones lambda. En el siguiente ejemplo use el Select para devolver todas las filas de Empleados que cumplan con la condición de tener 33 años y mostrar sus nombres.
using (EmpresaSAEntities data= new EmpresaSAEntities())
{
IQueryable<string> nombreEmpleados = data.EmpleadosSet
.Where(e=> e.Edad == 33)
.Select(p => p.Nombre);
Console.WriteLine("Nombre Empleados:");
foreach (var nombre in nombreEmpleados)
{
Console.WriteLine(nombre);
}
}
Para ambas sintaxis es posible usar operadores estándar para confeccionar consultas de agrupación (GroupBy), de combinación (Join o GroupJoin), de ordenamiento (OrderBy combinado con ThenBy o ThenByDescending por ejemplo), etc. Algunas operaciones de consulta como Count o Max, no tienen ninguna cláusula de expresión equivalente y, por tanto, deben expresarse como una llamada a método. La sintaxis de método se puede combinar con la sintaxis de consulta de varias maneras.
Como programador, tenemos la posibilidad de escribir la consulta mediante sintaxis de consulta como también con sintaxis de método. Sin embargo, en la mayoría de los casos, la sintaxis de consulta es más fácil y concisa porque utiliza muchas construcciones de lenguaje de C# familiares. Si bien, no existe ninguna diferencia semántica o de rendimiento entre las dos formas, las expresiones de consulta suelen ser más legibles que las expresiones equivalentes escritas con sintaxis de método. Un claro ejemplo que nos llevo a cambiar por sintaxis de consulta en el proyecto del que formo parte, es que la sintaxis de método resulta casi ilegible al tener una consulta con una gran cantidad de Joins o GroupJoins en secuencia donde los datos son seleccionados mediante clases anónimas. Veamos este caso:
Ejemplo con sintaxis de consulta basada en método:
//Join entre la tabla PermisosSet con los EmpleadosSet
//para obtener los ids de Empresa y Articulo.
var permisos = data.PermisosSet
.Join(data.EmpleadosSet,
p => p.IdLegajo,
e => e.IdLegajo,
(p, e) => new
{
p.IdEmpresa,
p.IdArticulo
});
//Join entre el IQueryable de "permisos" con los
//EmpresasSet para obtener información de la Empresa.
var resultadoConEmpresas = data.EmpresasSet
.Join(permisos,
em => em.IdEmpresa,
p => p.IdEmpresa,
(e, p) => new
{
p.IdArticulo,
DatosEmpresas = new
{
em.CodEmpresa,
em.Descripcion
}
});
//Join entre el IQueryable de " resultadoConEmpresas " con
//los ArticulosSet para obtener información del Articulo.
var resultadoFinal = data.ArticulosSet
.Join(resultadoConEmpresas,
a => a.IdArticulo,
r => r.IdArticulo,
(a, r) => new
{
DatosArticulos = new
{
a.CodArticulo,
a.Descripcion,
a.Vigencia
}
});
Ejemplo con sintaxis de expresiones de consulta:
var permisos = from r in data.PermisosSet
//Realizar todos los Joins
join e in data.EmpleadosSet on r.IdLegajo equals e.IdLegajo
join em in data.EmpresasSet on r.IdEmpresa equals em.IdEmpresa
join a in data.ArticulosSet on r.IdArticulo equals a.IdArticulo
//El Select se realiza al final para obtner todos los datos que se retornaran.
select new
{
DatosEmpresas = new
{
em.CodEmpresa,
em.Descripcion
},
DatosArticulos = new
{
a.CodArticulo,
a.Descripcion,
a.Vigencia
}
};
Si bien las consultas devuelven los mismos resultados puede verse claramente que la consulta confeccionada mediante sintaxis de expresiones es más legible y similar a T-SQL que la realizada son sintaxis de métodos.
ADO.NET, Entity Framework
ef, ado.net