framework .net 3.5 10 linq

43
LINQ Novedades en VB.NET 9.0 y C# 3.0 Nuevas funcionalidades en el lenguaje Nuevos compiladores Nuevo IDE en Visual Studio y diseñadores gráficos Soporte para LINQ (Language Integrated Query) Manteniendo, eso sí, la compatibilidad hacia atrás, casi al 100%. Las funcionalidades añadidas asociadas a LINQ son: Sintaxis de consulta de datos. Variables implícitamente tipadas. Tipos anónimos. Inicializadores de objetos. Métodos de extensión. Expresiones Lambda. Las cuales pasaremos a ver a continuación para poder entender LINQ y su uso.

Upload: antonio-palomares-sender

Post on 10-May-2015

2.810 views

Category:

Technology


6 download

TRANSCRIPT

Page 1: Framework .NET 3.5 10 Linq

LINQ

Novedades en VB.NET 9.0 y C# 3.0Nuevas funcionalidades en el lenguajeNuevos compiladoresNuevo IDE en Visual Studio y diseñadores gráficosSoporte para LINQ (Language Integrated Query)

Manteniendo, eso sí, la compatibilidad hacia atrás, casi al 100%.

Las funcionalidades añadidas asociadas a LINQ son:Sintaxis de consulta de datos.Variables implícitamente tipadas.Tipos anónimos.Inicializadores de objetos.Métodos de extensión.Expresiones Lambda.

Las cuales pasaremos a ver a continuación para poder entender LINQ y su uso.

Page 2: Framework .NET 3.5 10 Linq

LINQ

[C#]String nombre1 = “John”; // Declarada explícitamente como stringVar nombre2 = “John”; // Implícitamente asumida como stringConsole.WriteLine(nombre2.GetType().Name); // Devuelve “String”Int edad1 = 34; // ExplícitamenteintegerVar edad2 = 34; // Inferida como integerConsole.Writeline(edad2.GetType().Name); // Devuelve “Int32”

[VB]Dim nombre1 As String = “John” ‘Explícitamente stringDim nombre2 = “John” ‘Implícitamente asumida como stringConsole.WriteLine(nombre2.GetType().Name) ‘ Devuelve “String”Dim edad1 As Integer = 34 ‘ Explícitamente integerDim edad2 = 34 ‘ Implícitamente asumida como integerConsole.Writeline(edad2.GetType().Name ‘ Devuelve “Int32”

Variables implícitamente tipadas:El tipo se deduce por parte del compilador y del Intellisense, en base al valor de inicialización.Fuertemente tipadas, no son generalizaciones del tipo “Variant”, pero serán del tipo más general “31/12/09” será un String.

Page 3: Framework .NET 3.5 10 Linq

LINQ

List<Persona> gente = new List<Persona>(); [C#]Persona P = new Persona();P.Nombre = “Pepe”;P.Apellido = “Pérez”;P.Edad = 52;Gente.Add(P);// Nueva versión con inicializadoresGente.Add(new Persona{Nombre=“Pepe”,Apellido=“Pérez”,Edad=52});

Dim gente As New List(Of Persona) [VB]Dim P As New personaP.Nombre = “Pepe”P.Apellido = “Pérez”P.Edad = 52Gente.Add(P)Gente.Add(New Persona With {.Nomre=“Pepe”,.Apellido=“Pérez”,.Edad=52})

Inicializadores de objetos.Nos permiten asignar valores a todos los campos y propiedades accesibles de un objeto en el momento de la creación sin tener que invocar explícitamente un constructor del mismo.

Page 4: Framework .NET 3.5 10 Linq

LINQ

[C#]var Empleado = new {Nombre=“Juan Gómez”, Edad=33};[VB]Dim Empleado = New With {.Nombre=“Juan Gómez”, .Edad=33}

Tipos anónimosNo es necesario declarar la clase.Se infiere el tipo de forma similar a las variables implícitamente tipadas.No dispondremos de nombre de clase, este será generado por el compilador heredando directamente de Object, por lo que no podremos referir a dicho nombre, motivo por el que son llamados anónimos.Están fuertemente tipados.No son apropiados si se ha de compartir la información con miembros o terceros, al no poder acceder al nombre de clase generado.

Page 5: Framework .NET 3.5 10 Linq

LINQ

Tipos anónimos (II)Antes de decidirse a crear un objeto como una instancia de una clase anónima es necesario plantearse si esta es la mejor opción en ese caso.Si se desea crear objetos temporales y no hay necesidad de otros campos o métodos, un tipo anónimo puede ser una excelente solución.También pueden ser útiles si se necesita cambiar las propiedades en cada declaración o cambiar el orden de las mismas.Pero las limitaciones inherentes a los tipos anónimos hacen que no sean viables cuando debamos compartir información, al no aparecer la clase relacionada en ningún momento en el código y, por ende, ser imposible hacer referencia a la clase o pasarla como parámetro, al no poder declarar el tipo.

Page 6: Framework .NET 3.5 10 Linq

LINQ

public static class DemoExtensiones {public static int CuentaPalabras(this String Frase) {

return Frase.Split(new char[] {‘ ‘, ‘,’,’.’}).Length;}

}class Extensiones {

public void ExtensionesDetexto(){String FrasePrueba = “Esta es la prueba”;Console.WriteLine(FrasePrueba.CuentaPalabras());// Devuelve 4

}}

Métodos de extensión en C#Estos métodos son un complemento que nos permite la ilusión de estar añadiendo nuevos métodos de clase (static) a una clase existente, sin cambiar su definición, heredarla o tener que recompilar, accediendo a ellos como si fueran métodos de instancia.

Se definen como métodos static, anteponiendo “this” a primer parámetro.Se llaman mediante una instancia específica.Se asocian al tipo de dato del primer parámetro (this).

Page 7: Framework .NET 3.5 10 Linq

LINQ

Imports System.Runtime.CompilerServicespublic Module UtilidadesGenerales

<Extension()> Public Function CuentaPalabras(ByVal Frase As String) As Integer

return Frase.Split(new char() {‘ ‘, ‘,’,’.’}).LengthEnd Function

End ModulePublic Class Extensiones

public Sub ExtensionesDetexto()Dim FrasePrueba As String = “Esta es la prueba”MsgBox(FrasePrueba.CuentaPalabras)// Devuelve 4

End SubEnd Class

Métodos de extensión en Visual BasicEstos métodos son un complemento que nos permite la ilusión de estar añadiendo nuevos procedimientos Sub o Function a una clase existente, sin cambiar su definición, heredarla o tener que recompilar.

Hay que importar System.Runtime.CompilerServicesLas extensiones se definen en Modules.Hay que añadir el atributo <Extension()> al procedimiento.Se asocia al tipo del primer parámetro.

Page 8: Framework .NET 3.5 10 Linq

LINQ

Uso de los métodos de extensión en LINQ

Los métodos de extensión más comunes son los operadores estándar de LINQ, los cuales añaden funcionalidad a los tipos ya existentes en System.Collections.Ienumerable y System.Collections.Generic.Ienumerable(T).

Para usar los operadores estándar de LINQ habremos de importar la directiva System.Linq.

A partir de ese momento, cualquier tipo que implemente IEnumerable(Of T) parecerá disponer de métodos de instancia como GroupBy, OrderBy, Average, etc.

Se pueden ver todos estos métodos desde IntelliSense, tras pulsar el punto en una de estas instancias (Ej: List(Of T) o Array.

Page 9: Framework .NET 3.5 10 Linq

LINQ

[C#]// Buscamos números pares en una lista ya construidaNumerosPares = LosNumeros.FindAll(N => N % 2 == 0);// Frente aPublic static bool EsPar(int N) {

return N % 2 == 0;}NumerosPares = LosNumeros.FindAll(new Predicate<int>(EsPar));

[VB]‘Buscamos números pares en una lista ya construidaNumerosPares = LosNumeros.FindAll(Function(N As Integer) N Mod 2 = 0)‘ Frente aPublic Shared Function EsPar(ByVal N As Integer) As Boolean Return N Mod 2 = 0 End FunctionEvenNumbers = AllNumbers.FindAll(New Predicate(Of Integer) (AddressOf EsPar))

Expresiones Lambda.Las expresiones Lambda son funciones sin nombre que calculan y devuelven un valor único y pueden ser utilizados en el mismo lugar que los tipos delegados.Pueden contener tanto expresiones como sentencias.Son el mecanismo utilizado para implementar muchas de las funciones de consulta de LINQ (Where, Select, Order By, …)

Page 10: Framework .NET 3.5 10 Linq

LINQ

Expresiones Lambda (II)

Expresión Resultado Tipo devuelto

X => x + 1Function (x) x + 1

Si x=1, resultado = 2 Integer

X => x == 5Function (x) x = 5

Si x = 5, True, else False Boolean

(x,y) => x + yFunction (x,y)= x + y

Si x = 2 e Y = 3, 5 Integer

(x,y) => x == yFunction (x,y) x = y

Si x = y, True else False Boolean

Page 11: Framework .NET 3.5 10 Linq

LINQ

¿Qué es LINQ? Language Integrated QueryEs un conjunto de operadores de consulta que pueden utilizarse para consultar, extraer o filtrar datos.Sólo puede acceder a datos suministrados por Linq Providers, los cuales encapsulan los datos fuente como objetos accesibles por las consultas Linq.Disponible en C# 3.0 y Visual Basic .NET 9.0.Otros lenguajes tendrán soporte para Linq más adelante.Suministra librerías de clases para el conocimiento de los datos desde el código.Lo cual nos da las ventajas de la validación de sintaxis en tiempo de compilación y desde IntelliSense.Su principal objetivo es el de la consulta de los datos referenciados, aunque algunos Linq Providers permiten la actuación sobre dichos datos para su modificación.

Page 12: Framework .NET 3.5 10 Linq

LINQ

Antes del desarrollo de LINQ, los desarrolladores teníamos que conocer el lenguaje de consulta específico para cada tipo de origen de datos.Ahora LINQ nos ofrece un modelo único de trabajo sobre datos, independientemente de su origen, sólo necesitaremos dominar un lenguaje de consulta de datos para acceder a colecciones de objetos, XML, DataSets, bases de datos, … etc.Aunque un conocimiento de la técnicas subyacentes siempre será beneficioso y permitirá optimizar nuestros procesos, como ocurre con todas las tecnologías de abstracción por capas.LINQ permite consultar un limitado conjunto de datos, aquellos suministrados por los Linq Data Providers:

LINQ to ObjectsLINQ to Datastes.LINQ to XML.LINQ to Entities.LINQ to SQL.LINQ Data Providers de teerceros (Line Of Business Apps, Sharepoint, …) > 100.

Page 13: Framework .NET 3.5 10 Linq

LINQ

Query sintaxImplicity Typed VariablesAnonymous TypesObject InitializersExtension MethodsLambda Expressions

Page 14: Framework .NET 3.5 10 Linq

LINQ

Requerimientos de LINQ

Referencias en el proyecto:

System.Core

System.Xml.Linq

System.Data.Linq

System.Data-DataSetExtensions

Espacios de nombres a importar:

System.Linq

System.Xml.Linq

System.Data.Linq

Compilación:

Activar la opción de inferencia de tipos “Option Infer On”

Page 15: Framework .NET 3.5 10 Linq

LINQ

LINQ Data Providers

Page 16: Framework .NET 3.5 10 Linq

LINQ

‘Primer paso: Preparar datos de ejemploDim Gente As New List(Of Persona)Gente.Add(New Persona With{.Nombre=“Juan”, .Apellido=“Pérez”, .Edad=33})Gente.Add(New Persona With{.Nombre=“Pepe”, .Apellido=“Gómez”, .Edad=50})Gente.Add(New Persona With{.Nombre=“Leon”, .Apellido=“García”, .Edad=27})

‘Segundo paso: Definir la consultaDim Consulta = Gente.Where(Function(P) P.Edad >= 30)

‘Tercer paso: Ejecutar la consultaFor Each TreintaYTantos In Consulta

Console.WriteLine({0} & “ “ & {1}, TreintaYTantos.Nombre, TreintaYTantos.Apellido)

Next

Consultas LINQPara ejecutar una consulta LINQ se deben seguir estos tres pasos:

Configurar un origen de datos.Definir la consulta.Ejecutar la consulta.

Este es un ejemplo muy sencillo, pero en el caso de otros orígenes de datos se requerirán:

Dataset: necesitaremos un objeto DataSet adecuadamente rellenado con datos.Base de datos: deberemos configurar un DatContext, mediante LINQ to Entities o LINQ to SQL, que contenga una conexión a base de datos y los metadatos adecuados.

Aquí simplemente se escribe una consulta utilizando los operadores de LINQ del lenguaje de nuestra elección.Habitualmente las consultas no se ejecutan en este paso, salvo que contengan funciones de agregado.Adicionalmente, esta consulta en particular hace uso de un método de extensión (Where) al que se le pasa una expresión Lambda.

Page 17: Framework .NET 3.5 10 Linq

LINQ

‘ Segundo paso: Definir la consulta[C#]var TreintaYTantos = from P in Gente

where P.Edad >= 30 select P.Nombre;

[VB]Dim TreintaYTantos = From P In Gente _

Where P.Edad >= 30 _ Select P.Nombre

Opciones de sintaxis de LINQ

Utilizar los métodos de extensión, aunque muy potentes y con un excelente rendimiento, no redunda en la legibilidad del código, más bien le añade un nivel más de densidad.

Otra opción, que generará el mismo código intermedio por parte del compilador, para el ejemplo anterior, sería:Aquí indicamos nuestro origen de datos, en este

caso la colección Gente, que en el ámbito de la consulta será conocida por P, y que será del tipo Persona, inferido del contenido de la lista.

Aquí filtramos los elementos a recuperar mediante el valor de una de las propiedades del tipo contenido en el origen de datos.

Finalmente, aquí indicamos el aspecto que tendrá el resultado de ejecutar esta consulta. Podríamos haber recuperado el objeto completo de cada elemento de la lista que cumpla la condición. Como sólo recuperamos una propiedad de tipo String, pero puede haber más de un resultado en la consulta, el tipo devuelto será una colección de String.

Utilizamos una variable de tipo implícito, cuyo tipo será inferido del resultado de la consulta. En este caso, una lista de nombres, por lo que el tipo será System.Collection.Generic.IEnumerable<String>

Page 18: Framework .NET 3.5 10 Linq

LINQ

Operadores de consulta LINQLas funciones son las mismas disponibles en SQL, aunque algún operador cambia de nombre (Take = Top)

Operador Descripción

Selección Select<expr>, SelectMany<expr>

Filtro Where<expr>, Distinct

Condición Any(<expr>), All(<expr>), Contains(<expr>)

Unión <expr> Join <expr> On <expr> Equals <expr>

Agrupación Group By <expr>, <expr> Into <expr>, <expr>Group Join <decl> On <expr> Equals <expr>Into <expr>

Agregación Count([<expr>]), Sum(<expr>), Min(<expr>), Max(<expr>), Avg(<expr>)

Partición Skip [ While ] <expr>, Take [ While ] <expr>

Conjunto Union, Intersect, Except

Ordenación Order By <expr>, <expr> [Ascending | Descending]

Page 19: Framework .NET 3.5 10 Linq

LINQ

Proveedores de datos – LINQ To ObjectsEs una nueva forma de trabajar con las colecciones, muy superior al tradicional bucle For Each, ya que LINQ nos ofrece herramientas para filtrar, ordenar y agrupar los elementos de la lista de objetos. Adicionalmente, es más fácil leer y comprender una instrucción LINQ que seguir toda la lógica del código dentro de un bucle For Each, el cual puede ser muy largo.

Ventajas con respecto a los bucles For Each :Conciso y legible.Con herramientas de filtrado, ordenación y agrupación.Migrable a otras fuentes de datos sin apenas cambios.

Listas IEnumerable o IEnumerable<T> consultables:List<T> / List (Of Type)ArrayDictionary(Tkey, Tvalue)

Page 20: Framework .NET 3.5 10 Linq

LINQ

[VB] Version tradicionalPrivate Class Clasificador Implements IComparer(Of Persona) Public Function Compare(ByVal x As Persona, ByVal y As Persona) _ As Integer Implements System.Collections.Generic.IComparer _ Of Persona).Compare If x.Ciudad <> y.Ciudad Then Return New CaseInsensitiveComparer().Compare(x.Ciudad, y.Ciudad) Else Return New CaseInsensitiveComparer().Compare(x.Edad, y.Edad) End If End Function End Class 'Buscar a los mayores de 30, y ordenar por ciudad y edadDim Temporal As New List(Of Persona) For Each P As Persona In Gente If P.Edad >= 30 Then Temporal.Add(P) Next Temporal.Sort(New Clasificador)

Nueva versionDim TempResult = From P In Gente _ Where P.Edad >= 30 _ Order By P.Ciudad, P.Edad _ Select P ' Pero puede tener un 25% menos rendimiento que el For Each

Proveedores de datos – LINQ To Objects

Page 21: Framework .NET 3.5 10 Linq

LINQ

Proveedores de datos – LINQ To Dataset

Con el desarrollo separado por capas, es habitual que la capa de acceso a datos devuelva directamente un DataSet con la composición de DataTables y sus relaciones adecuadamente cumplimentada e informada.

El acceso a esta información podía ser muy fácil o muy difícil, siempre en función de la composición del Dataset y las relaciones entre las tablas que lo compongan.

Ahora se ha simplificado un poco este tipo de búsquedas ya que disponemos de un proveedor de datos para LINQ contra Datasets (tipados o no tipados), el cual permite acceder a uno o más Datasets simultáneamente, efectuar uniones entre DataTables o incluso entre DataTables y otros tipos de datos.

El acceso se efectúa al nivel DataTable en lugar de quedarse al nivel DataSet.

Page 22: Framework .NET 3.5 10 Linq

LINQ

[C#]// Rellenamos un DataSet tipadoVar DA = new dsProductsTableAdapters.ProductsTableAdapter();DA.Connection = DBConn;Var dtProductos = new dsProducts.ProductDataTable();DA.Fill(dtProductos);// Buscamos los 10 productos más carosVar MasCaros = (from P in dtProductos

orderby P.ListPrice descending select P.Take(10);

// Mostramos el resultadoForeach (var P in MasCaros) Console.WriteLine(String.Format("{0} – cuesta:{1}", P.Nombre,P.Precio));[VB]' Rellenamos un DataSet tipadoDim DA As New dsProductsTableAdapters.ProductsTableAdapterDA.Connection = DBConnDim drProductos As New dsProducts.ProductDataTableDA.Fill(dtProductos)' Buscamos los 10 productos más carosDim MasCaros = From P In dtProductos _

Order By P.Precio Descending _ Take 10 _ Select P

' Mostramos el resultadoFor Each P In masCaros Console.WriteLine(String.Format(("{0} – cuesta:{1}", P.Nombre,P.Precio))Next

Proveedores de datos – LINQ To Dataset (II)

Declaramos una variable cuyo tipo será inferido del resultado de la consulta, en este caso será una colección enumerable del tipo ProductRow

Especificamos la fuente de datos de la consulta, en este caso el DataTable antes definido sobre el DataSet, cuyo tipo devuelto será ProductRow, inferido del contenido del DataTable.

Utilizamos el operador Order By para especificar la ordenación deseada de los datos resultantes.

Indicamos que deseamos sólo las 10 primeras filas de resultados.

Se especifica que la consulta debe devolver el objeto ProductRow completo para cada fila del conjunto de resultados.

Page 23: Framework .NET 3.5 10 Linq

LINQ

Acceso a datos con LINQ

Esta herramienta tan potente nos permite acceder a datos almacenados mediante los siguientes orígenes de datos, adicionales a los ya revisados.

LINQ to XML

LINQ to Entities

LINQ to SQL

Page 24: Framework .NET 3.5 10 Linq

LINQ

LINQ to XMLNo es ningún secreto que XML es una metodología de implementación de archivos de texto de una forma estructurada que no puede ser dejada de lado por ningún desarrollador, ni ahora ni en un futuro próximo.Su implantación universal obliga a conocer y manipular adecuadamente este formato, por lo que .NET Framework 3.5 nos suministra nuevas herramientas para ello.

Nueva API XML (XElement, XAttribute, XNamespace, etc)Proveedor de datos para LINQ.

Los beneficios del uso de este estándar son:Es mejor y menos pesado que DOM.Es más fácil trabajar con este formato.Disponemos de validación en tiempo de compilación e InteliSense.Mejor soporte para depuración.Se puede cargar o serializar XML desde archivos o streams.Se puede crear y manipular árboles XML en memoria.Es comparable a XPATH, XSLT(W3C) y XQuery en funcionalidad.

Page 25: Framework .NET 3.5 10 Linq

LINQ

[C#]XElement Example1 = new XElement("Email", new XAttribute("Prioridad", "Alta"), new XElement("Destintario", "[email protected]"), new XElement("Asunto", "Ejemplo XML – nueva version"), new XElement("Cuerpo", new XElement("Linea 1", "Mas facil de usar"), new XElement("Linea 2", "Potente y productivo"))); [VB]Dim Example1 As New XElement("Email", _ New XAttribute("Prioridad", "Alta"), _ New XElement("Destinatario", "[email protected] "), _ New XElement("Asunto", "Ejemplo XML – nueva version "), _ New XElement("Cuerpo", _ New XElement("Linea 1", "Mas facil de usar "), _ New XElement("Linea 2", "Potente y productivo ")))

LINQ to XML(II) – Creación de árboles XMLBasándonos en los nuevos tipos de datos XML podemos crear fácilmente árboles XML:

Desde código.Desde archivos de texto, TextReader o direcciones Web.Mediante un XmlReader (Xnode.ReadFrom)

XML Generado:<?xml version="1.0" encoding="utf-8"?><Email Prioridad="Alta"> <Destinatario>[email protected]</Destinatario> <Asunto>Ejemplo XML – nueva version</Asunto> <Cuerpo> <Linea 1>Mas facil de usar</Linea 1> <Linea 2>Potente y productivo</Linea 2> </Cuerpo></Email>

Page 26: Framework .NET 3.5 10 Linq

LINQ

Dim Test = <Email Prioridad="Alta"> <Destinatario>[email protected]</Destinatario> <Asunto>¡Ahora <%= Now.ToShortDateString %>, VB.NET!</Asunto> <Cuerpo> <Linea 1>Literales XML - conciso, legible, claro</Linea 1> <Linea 2>Muy faciles de usar, muy potentes</Linea 2> </Cuerpo></Email>Console.WriteLine(Test.@Prioridad & " prioridad del correo a & Test.<Destinatario>.Value)

LINQ to XML(III) – Literales XML en Visual BasicPermiten teclear (o pegar) texto XML directamente en el código, ya que tiene el mismo aspecto que el XML final.Tienen en cuenta los esquemas XML aplicables.Permiten anidar código.Soportan los espacios de nombres XML.No requieren carácter de continuación de línea.Permiten el uso de IntelliSense si hay un esquema aplicable.

Expresiones embebidas Elemento Atributo

Page 27: Framework .NET 3.5 10 Linq

LINQ

[C#]var XMLData = XDocument.Load("c:\\code\\xmltest6.xml");var ThirtyLondon = from P in XMLData.Descendants("Person")

orderby P.Element("Age").Value where P.Element("City").Value == "London" select new {Name = P.Attribute("Name").Value,

Age = P.Element("Age").Value,City = P.Element("City").Value};

[VBDim XMLData = XDocument.Load("c:\code\xmltest6.xml")Dim ThirtyLondon = From P In XMLData.<People>.<Person> _

Where P.<Age>.Value > 30 And _ P.<City>.Value = "London" _

Order By P.<Age>.Value _ Select New With {.Name = P.@Name, _

.Age = P.<Age>.Value, _

.City = P.<City>.Value}

LINQ to XML(IV) – ConsultasSe pueden realizar consultas sobre tipos XDocument y XElement.Es similar, pero más rápido y fácil que XPath o XQuery.Se puede obtener el mismo resultado que con XSLT, pero con menos código y esfuerzo.

File: xmltest6.xml<?xml version="1.0" encoding="utf-8"?><People>

<Person Name="John "><Age>33</Age><City>London</City>

</Person><Person Name="Sally ">

<Age>31</Age><City>London</City>

</Person><Person Name="Alexander ">

<Age>26</Age><City>London</City>

</Person><Person Name="Sue ">

<Age>32</Age><City>London</City>

</Person></People>

Page 28: Framework .NET 3.5 10 Linq

LINQ

LINQ to EntitiesEsta funcionalidad de LINQ está íntimamente ligada a ADO.NET Entity Framework, por lo que empezaremos por hablar de esta nueva funcionalidad de acceso a datos de la versión 3.5.La mayoría de nuestras aplicaciones están construidas sobre una base de datos relacional, por lo que es evidente que, de alguna forma, habrán de interactuar con dicha base de datos.La estructura de tablas de las bases de datos no siempre es óptima para su acceso desde código y el modelo conceptual suele diferir mucho del modelo físico de los datos.El Entity Data Model de ADO.NET Entity Framework es la solución a este tipo de problemas ya que se construye un modelo "lógico" de los datos, definiendo el correspondiente interfaz con el modelo físico, permitiendo el acceso desde código mediante una construcción simplificada y adecuada de los datos, con un enfoque orientado a objetos, aunque los datos subyacentes no estén en este formato.Con lo que ADO.NET nos presenta las entidades de datos como objetos en el entorno, mediante el Object Services, lo cual los hace idóneos para ser atacados desde LINQ.

Page 29: Framework .NET 3.5 10 Linq

LINQ

LINQ to Entities (II)

Al ser una primera versión, está claro que, como siempre, necesitará pulirse un poco para alcanzar su pleno potencial, pero ya es una herramienta muy potente y que facilita enormemente el trabajo de desarrollo en cuanto al acceso a datos y simplifica el desarrollo de las capas de acceso a datos.

LINQ to Entities es el proveedor de datos de LINQ especializado en el acceso a este tipo de origen de datos orientados a objetos, sobre el que sólo se podrán efectuar consultas y recuperación de datos, pero no modificación, al menos en esta fase temprana de implantación de la herramienta, ya que mediante Entity Framework sí que podemos acceder a los datos en modificación.

Hay dos formas de consultar datos en el Entity Framework:

LINQ to Entities

Entity SQL, utilizando comandos ADO.NET

Page 30: Framework .NET 3.5 10 Linq

LINQ

LINQ to Entities (III) Entity Framework

ADO.NET

Entity .Framework

Modelo conceptual(EDM – Objetos de negocio)

Mapping(Relaciona los modelos conceptual y lógico)

Modelo lógico(El de la base de datos)

Uno de los objetivos de ADO.NET 3.5 es el de abstraer al desarrollador de la complejidad de los datos subyacentes y presentar un modelo conceptual de objetos (entidades).Para ello utiliza una arquitectura en 3 capas las cuales, una vez definidas las relaciones, se encargarán de gestionar automáticamente el enlace entre los objetos y los datos reales.

Este modelo conceptual facilita la encapsulación de la complejidad de los datos hacia el programador y la posible evolución del esquema de la base de datos, sin afectar al código.

Page 31: Framework .NET 3.5 10 Linq

LINQ

LINQ to Entities (IV) Entity FrameworkEn muchos casos el acceso a la base de datos puede resultar más complejo de que inicialmente parecía y el nivel de conocimiento de la estructura de los mismos condiciona el código y la funcionalidad que se puede desarrollar.

Modelo Conceptual

Modelo Lógico

Mapping

SELECT p.FirstName, p.LastName, s.Email, s.Department FROM People p inner join Staff s on p.PersonID = s.PersonID WHERE p.City = 'Seattle'’

[C#]var Trainers = from T in TrainingContext.People.OfType<Trainer>() where T.City == "Seattle" select new {Firstname = T.FirstName, Lastname = T.LastName, Email = T.Email, Department = T.Department}; [VB]Dim Trainers = From T In TrainingContext.People.OfType(Of Trainer)() _ Where T.City = "Seattle" _ Select New With {.Firstname = T.FirstName, _ .Lastname = T.LastName, _ .Email = T.Email, _ .Department = T.Department}

SELECT p.FirstName, p.LastName, c.CourseName, c.Track FROM People p inner join Staff s on p.PersonID = s.PersonID inner join TrainerCourses tc on s.PersonID = tc.TrainerID inner join Courses c on tc.CourseID = c.CourseID WHERE P.City = 'Seattle'

[C#]var Trainers = from T in TrainingContext.People.OfType<Trainer>() where T.City == "Seattle" select new { Firstname = T.FirstName, Lastname = T.LastName, Courses = from C in T.Courses select new {CourseName = C.CourseName, Track = C.Track}}; [VB]Dim Trainers = From T In TrainingContext.People.OfType(Of Trainer)() _ Where T.City = "Seattle" _ Select New With {.Firstname = T.FirstName, _ .Lastname = T.LastName, _ .Courses = From C In T.Courses _ Select New With {.CourseName = C.CourseName, _ .Track = C.Track}}

Tipos anónimos

Page 32: Framework .NET 3.5 10 Linq

LINQ

LINQ to Entities (V)La estructura del Entity Framework

Fuentes de datos

ADO.NET Data Providers

Command Tree

EntityClient Data Provider

Command Tree

Object Services

LINQ to Entities

EntityDataReader

DBDataReader

IEnumerable<T>

Entity SQL

Query

Entity SQL

Query

EDM

Modelo Conceptual

Modelo Lógico

Mapping

Page 33: Framework .NET 3.5 10 Linq

LINQ

LINQ to Entities (VI)

Un vez definido nuestro modelo de entidades dispondremos de formas de consultar los datos:

La tradicional, con sentencias de SQL/Transact-SQL.

Utilizando consultas de Entity SQL contra el EDM.

Atacar al EDM mediante LINQ to Entities.

De hecho, construyen unas sobre otras, es decir, si atacamos mediante LINQ to Entities, habrá una traducción a Entity SQL por detrás, la cual, a su vez, se verá traducida a las correspondientes sentencias Transact-SQL para el acceso a los datos reales en la base de datos.

Lo que desconoceremos, normalmente, es dónde se realizarán estas traducciones, ya que dependerá del soporte al modelo Entity Framework que suministre el servidor de la base de datos.

Page 34: Framework .NET 3.5 10 Linq

LINQ

LINQ to Entities (VII)

Acceder al Entity Framework mediante LINQ to EntitiesLas consultas entrarán en el ámbito de un "ObjectContext".El cuál gestionará encapsulando el acceso a la capa de Object Services:

La conexión(es) con la(s) base(s) de datos.Los metadatos de los modelos (Conceptual, mapping y lógico)La gestión del estado de los objetos (modificaciones, eliminaciones, nuevos…)

Una instancia de ObjectContext se utiliza para:Acceder a los datos como objetos.Enlazar los resultados de las consultas (shape).Añadir, cambiar o eliminar objetos.Conservar los cambios en la fuente de datos.Hacer attach y detach de objetos en memoria.Serializar objetos, mediante el soporte a WCF.Gestionar las identidades de objetos y rastrear los cambios.Gestionar la concurrencia.Gestionar las conexiones.Gestionar las transacciones.

Page 35: Framework .NET 3.5 10 Linq

LINQ

[C#]public static void Demo1() { var TrainingContext = new TrainingEntities(); var Trainers = from T in TrainingContext.People

where T.City == "Seattle" select T;

foreach (var T in Trainers) Console.WriteLine(String.Format("Name: {0} {1}", T.FirstName,

T.LastName )); }[VB]Public Shared Sub Demo1() Dim TrainingContext = New TrainingEntities Dim Trainers = From T In TrainingContext.People _

Where T.City = "Seattle" _ Select T

For Each T In Trainers Console.WriteLine(String.Format("Name: {0} {1}",T.FirstName, _

T.LastName)) Next End Sub

LINQ to Entities (VIII)

Page 36: Framework .NET 3.5 10 Linq

LINQ

LINQ to Entities (IX) La obtención de los resultados de la consulta se difiere hasta que dichos resultados sean necesarios.Los objetos relacionados no se cargan automáticamente, como en LINQ to SQL, sino que hemos de especificarlo explícitamente mediante el método Load de las propiedades de navegación, el cual nos devolverá una EntityCollection o EntityReference.Salvo que sepamos de antemano que un objeto relacionado será necesario, en cuyo caso puede ser "incluido" en la consulta.

public static void Demo9() { var TrainingContext = new TrainingEntities(); var Trainers = from T in TrainingContext.People.OfType<Trainer>()

where T.City == "Seattle" select T;

foreach (var T in Trainers) { Console.WriteLine(String.Format("Name: {0} {1}", T.FirstName, T.LastName)); // Now explicitly load this Trainer's courses. T.Courses.Load(); foreach (var C in T.Courses) Console.WriteLine(" Course: " + C.CourseName); } }

Dim TrainingContext = New TrainingEntities() Dim Trainers = From T In TrainingContext.People.OfType(Of Trainer)().Include("Courses") _

Where T.City = "Seattle" _ Select T

For Each T In Trainers Console.WriteLine([String].Format("Name: {0} {1}", T.FirstName, T.LastName)) For Each C In T.Courses Console.WriteLine(" Course: " & C.CourseName) Next Next

Page 37: Framework .NET 3.5 10 Linq

LINQ

LINQ to Entities (X) – Traducción de las consultasDim CoursesInSeattle = From C In TrainingCtx.Courses _ Where (From T In TrainingCtx.People.OfType(Of Trainer)() _ Where T.City = "Seattle" _ And T.Courses.Any(Function(F) F.CourseID = C.CourseID) _ Select T).Count > 1 _ Select C.CourseName

eCom.CommandText = "SELECT C " & _ "FROM TrainingEntities.Courses as C " & _ "WHERE COUNT(select VALUE Trainer.PersonID " & _ "from C.Trainer " & _ "where Trainer.City = Seattle') > 1"

SELECT [Project3].[CourseName] AS [CourseName] FROM ( SELECT [Extent1].[CourseName] AS [CourseName], ( SELECT COUNT(cast(1 as bit)) AS [A1] FROM [dbo].[People] AS [Extent2] LEFT OUTER JOIN ( SELECT [Extent3].[PersonID] AS [PersonID], cast(1 as bit) AS [C1] FROM [dbo].[Staff] AS [Extent3] ) AS [Project1] ON [Extent2].[PersonID] = [Project1].[PersonID] WHERE ( CASE WHEN ( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL))) THEN '2X' ELSE '2X0X' END LIKE '2X0X%' ) AND (N'Seattle' = [Extent2].[City]) AND ( EXISTS ( SELECT cast(1 as bit) AS [C1] FROM ( SELECT [TrainerCourses].[CourseID] AS [CourseID], [TrainerCourses].[TrainerID] AS [TrainerID] FROM [dbo].[TrainerCourses] AS [TrainerCourses] ) AS [Extent4] WHERE ([Extent2].[PersonID] = [Extent4].[TrainerID]) AND ([Extent4].[CourseID] = [Extent1].[CourseID]) ) ) ) AS [C1] FROM [dbo].[Courses] AS [Extent1]) AS [Project3] WHERE [Project3].[C1] > 1

Page 38: Framework .NET 3.5 10 Linq

LINQ

Entity Framework, añadir datosPara añadir datos mediante el Entity Framework deberemos:

Crear un nuevo objeto del tipo adecuado.Informar todas sus propiedades, al menos las obligatorias.Ejecutar el método AddToXXX correspondiente.Salvar los cambios en el origen de datos.

[C#]//Crear un ObjectContext. var TrainingCtx = new TrainingEntities();// Paso 1: Crer un objeto Trainer e informar sus propiedadesvar NewTrainer = Trainer.CreateTrainer(22, "Carol", "Smith", "Training", "[email protected]", "cs705", "Mrs");// Paso 2: Informar también las no obligatorias NewTrainer.City = "London";NewTrainer.Phone = "555-54321";// Paso 3: Añadir el Trainer a las colleccionesTrainingCtx.AddToPeople(NewTrainer);// Paso 4: Salvar los cambiosTrainingCtx.SaveChanges();[VB]'Crear un ObjectContext.Dim TrainingCtx = New TrainingEntities'Paso 1: Crer un objeto Trainer e informar sus propiedadesDim NewTrainer = Trainer.CreateTrainer(16, "Peter", "Willford", _"Training", "[email protected]","pw706", "Mr")' Paso 2: Informar también las no obligatorias NewTrainer.City = "London"NewTrainer.Phone = "555-889767"' Paso 3: Añadir el Trainer a las colleccionesTrainingCtx.AddToPeople(NewTrainer)' Paso 4: Salvar los cambiosTrainingCtx.SaveChanges()

Page 39: Framework .NET 3.5 10 Linq

LINQ

LINQ to SQLAunque la metodología preferida será en un futuro próximo LINQ to Entities, ya que Microsoft ha comunicado que no habrá actualizaciones ni mejoras al LINQ to SQL, esta es, de momento, la metodología actual en muchas instalaciones, debido a su sencillez (relativa) y a que Entity Framework no estaba aún disponible o se considera una tecnología no lo suficientemente madura y sujeta a posibles cambios.Algunas de las características de esta tecnología son:

LINQ to SQL es una implementación de acceso mediante objetos a datos almacenados de forma relacional, utilizando para ello un modelo de objetos de datos.Permite un mapeo directo contra el esquema subyacente de SQL Server.Soporta tablas, transacciones, vistas y procedimientos almacenados.Permite la selección, inserción, actualización y eliminación de datos.Lógicamente estas funcionalidades se realizan mediante la traducción simultánea en ambos sentidos.

Page 40: Framework .NET 3.5 10 Linq

LINQ

[C#]var TrainingCtx = new LINQtoSQL.LINQtoSQLTrainingDataContext();var People = from P in TrainingCtx.Peoples

orderby P.LastName select P;

foreach (var P in People) { if (P.Staff != null) { Console.WriteLine("Trainer: {0} {1} Email:{2}", P.FirstName, P.LastName, P.Staff.Email); } else Console.WriteLine("Person: {0} {1}", P.FirstName, P.LastName);} [VB]Dim TrainingCtx = New LINQtoSQL.LINQtoSQLTrainingDataContextDim People = From P In TrainingCtx.Peoples _

Order By P.LastName _ Select P

For Each P In People If P.Staff IsNot Nothing Then Console.WriteLine("Trainer: {0} {1} Email:{2}", _ P.FirstName, P.LastName, P.Staff.Email) Else Console.WriteLine("Person: {0} {1}", P.FirstName, P.LastName) End IfNext

LINQ to SQL(II) – Sintaxis de consulta

Page 41: Framework .NET 3.5 10 Linq

LINQ

[c#]var TrainingCtx = new LINQtoSQL.LINQtoSQLTrainingDataContext(); //Desactivar Lazy Loading TrainingCtx.DeferredLoadingEnabled = false;

[VB]Dim TrainingCtx = New LINQtoSQL.LINQtoSQLTrain 'Desactivar Lazy Loading TrainingCtx.DeferredLoadingEnabled = False

LINQ to SQL(III)Como en el caso de LINQ to Entities, la ejecución de las consultas se difiere hasta que los resultados sean necesarios.Aunque la carga de datos relacionados está habilitada por defecto (Lazy Loading).Para desactivarla deberemos modificar las DataLoadOptions del objeto ObjectContext.

Page 42: Framework .NET 3.5 10 Linq

LINQ

[C#]var TrainingCtx = new LINQtoSQL.LINQtoSQLTrainingDataContext();var NewPerson = new LINQtoSQL.People();NewPerson.PersonID = 32;NewPerson.FirstName = "John";NewPerson.LastName = "Sawyer";NewPerson.City = "London";NewPerson.Phone = "555-32432";TrainingCtx.Peoples.InsertOnSubmit(NewPerson);TrainingCtx.SubmitChanges();[VB]Dim TrainingCtx = New LINQtoSQL.LINQtoSQLTrainingDataContextDim NewPerson = New LINQtoSQL.PeopleNewPerson.PersonID = 31NewPerson.FirstName = "John"NewPerson.LastName = "Sawyer"NewPerson.City = "London"NewPerson.Phone = "555-32432"TrainingCtx.Peoples.InsertOnSubmit(NewPerson)TrainingCtx.SubmitChanges()

LINQ to SQL(III) – Añadir datos

1º - Crear un nuevo objeto del tipo adecuado

2º - Cumplimentar sus propiedades

3º - pasar el objeto al método adecuado.

4º - Salvar los cambios para que se efectúe la inserción

Page 43: Framework .NET 3.5 10 Linq

LINQ

[C#]

var TrainingCtx = new LINQtoSQL.LINQtoSQLTrainingDataContext();var ThePerson = TrainingCtx.Peoples.Single(P => P.PersonID == 3);ThePerson.Phone = "555-33345";TrainingCtx.SubmitChanges();

LINQ to SQL(III) – Modificar datos

[VB]

Dim TrainingCtx = New LINQtoSQL.LINQtoSQLTrainingDataContextDim ThePerson = _ TrainingCtx.Peoples.Single(Function(P) P.PersonID = 3)ThePerson.Phone = "555-33345"TrainingCtx.SubmitChanges()