Herramientas de usuario

Herramientas del sitio


fw:othersnet:linq

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anterior Revisión previa
Próxima revisión
Revisión previa
fw:othersnet:linq [2009/03/22 09:37]
alfred
fw:othersnet:linq [2020/05/09 09:25] (actual)
Línea 1: Línea 1:
 ====== LINQ ====== ====== LINQ ======
 +===== Sintaxis =====
  
 +En ''​System.Linq''​ existen una serie de métodos de extensión que permiten hacer consultas sobre datos (sobre xml, bases de datos...). \\ \\ 
  
 +Los siguientes son ejemplos de consultas sobre elementos en memoria:
 +<code csharp>
 +IEnumerable<​Person>​ list = lPerson.Where(p => p.firstName.StartsWith("​A"​));​
 +int maxAge = lPerson.Max(p => p.age);
 +double avg = lPerson.Average(p => p.age);
 +</​code>​
 +Pero en LINQ existen lo que serían las sintaxis de expresiones para realizar este tipo de consultas. Estas son parecidas a las sentencias sql de toda la vida y empiezan siempre por **from** y acaban por **select** siguiendo una estructura como la que sigue:
 +<code csharp>
 +from elementos_a_consultar in lista select elementos_devueltos
 +</​code>​
 +Un ejemplo:
 +<code csharp>
 +IEnumerable<​Person>​ list = from p in lPerson select p;
 +</​code>​
  
 +===== Filtro y ordenación =====
  
 +También podemos agregar clausulas where y orderby:
 +<code csharp>
 +IEnumerable<​Person>​ list = from p 
 +    in lPerson ​
 +    where p.firstName.StartsWith("​A"​)
 +    orderby p.age
 +    select p;
 +</​code>​
 +En el código de arriba el trozo //from p in lPerson// indica lanzar una consulta LINQ sobre la colección ''​lPerson'',​ y que usaremos el parámetro ''​p''​ para representar a cada elemento que consultamos. En realidad, el nombre del parámetro ''​p''​ es irrelevante - podría haberlo llamado ''​o'',​ ''​x'',​ ''​person''​ o de cualquier otra forma. El trozo //select p// nos indica que queremos devolver una secuencia IEnumerable de objetos Person como resultado de la consulta. Esto esto pasa porque la colección ''​lPerson''​ contiene objetos de tipo ''​Person''​. Pero si quisieramos devolver los nombres sería algo así:
 +<code csharp>
 +IEnumerable<​string>​ list = from p 
 +    in lPerson ​
 +    where p.firstName.StartsWith("​A"​)
 +    orderby p.age
 +    select p.firstName;​
 +</​code>​
 +También podemos consultar los elementos relacionados o ordendar descendentemente:​
 +<code csharp>
 +IEnumerable<​string>​ categories = from c in Categories
 + where c.Products.Count > 5
 + orderby c.CategoryName descending
 + select c.CategoryName;​
 +</​code>​
 +Otro ejemplo sería el de devolver un objeto de una clase que no es la de los elementos de la lista:
 +<code csharp>
 +class AlternatePerson {
 + string nameAge { get; set; }
 +}
 +...
 +IEnumerable<​AlternatePerson>​ friends = from p in lPeople
 + where p.LastName.StartsWith("​G"​)
 + select new AlternatePerson {
 + nameAge = p.FirstName + p.Age;
 + }
 +</​code>​
  
 +===== Momento de la consulta =====
 +
 +Una de las principales características de la interface IEnumerable<​T>​ es que los objetos que las implementen pueden retrasar su ejecución hasta el momento en que se introduzca en un bucle (esto es posible gracias al ''​yield''​). LINQ usa esta ventaja, retrasando las consultas hasta la primera vez que se itere sobre el resultado. Si nunca se itera sobre una IEnumerable<​T>,​ entonces, la consulta nunca es ejecutada. Pero si lo que queremos es ejecutar inmediatamente la consulta (utilizando toList o toArray) haremos:
 +<code csharp>
 +List<​Category>​ categories = (from c in db.Categories
 + where c.CategoryName
 + select c).ToList();​
 +</​code>​
 +Si luego cambiasemos los datos de la lista inicial y volviesemos a iterarla, se volvería a ejecutar la query. Por ejemplo, en la siguiente aparece Juanjo en la segunda iteración:
 +<code csharp>
 +var list = from l in lPerson select l; 
 +foreach (Person p in list)
 +    Console.WriteLine(p.firstName);​
 +lPerson.Add(new Person() { firstName = "​Juanjo",​ age = 32 });
 +foreach (Person p in list)
 +    Console.WriteLine(p.firstName);​
 +</​code>​
 +
 +===== Ejemplos =====
 +
 +==== Sencillos ====
 +=== Where + and ===
 +<code csharp>
 +var expensiveInStockProducts =
 +        from p in products
 +        where p.UnitsInStock > 0 && p.UnitPrice > 3.00M
 +        select p;
 +</​code>​
 +
 +=== Buscar las palabras que tengan más letras que su valor ===
 +<code csharp>
 +string[] digits = { "​zero",​ "​one",​ "​two",​ "​three",​ "​four",​ "​five",​ "​six",​ "​seven",​ "​eight",​ "​nine"​ };
 +var shortDigits = digits.Where((digit,​ index) => digit.Length < index);
 +</​code>​
 +=== Cambiando el valor ===
 +<code csharp>
 +int[] numbers = { 5, 4, 1};
 +var numsPlusOne =
 +        from n in numbers
 +        select n + 1;
 +</​code>​
 +Devolvería 6 5 2
 +=== Combinar dos arrays ===
 +<code csharp>
 +int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
 +string[] strings = { "​zero",​ "​one",​ "​two",​ "​three",​ "​four",​ "​five",​ "​six",​ "​seven",​ "​eight",​ "​nine"​ };
 +var textNums =
 +        from n in numbers
 +        select strings[n];
 +</​code>​
 +Devolvería five, four, one...
 +
 +==== Grouping ====
 +
 +Coger una agrupación y el tipo de agrupación que es:
 +<code csharp>
 +var wordGroups =
 +                from w in words
 +                group w by w[0] into g
 +                select new { FirstLetter = g.Key, Words = g };
 +</​code>​
 +=== Anidación ===
 +<code csharp>
 +var customerOrderGroups =
 +                from c in customers
 +                select
 +                    new {c.CompanyName,​
 +                         ​YearGroups =
 +                             from o in c.Orders
 +                             group o by o.OrderDate.Year into yg
 +                             ​select
 +                                 new {Year = yg.Key,
 +                                      MonthGroups =
 +                                          from o in yg
 +                                          group o by o.OrderDate.Month into mg
 +                                          select new { Month = mg.Key, Orders = mg }
 +                                     }
 +                        };
 +</​code>​
 +
 +==== Tipado anónimo ====
 +<code csharp>
 +string[] words = { "​aPPLE",​ "​BlUeBeRrY",​ "​cHeRry"​ };
 +var upperLowerWords =
 +        from w in words
 +        select new {Upper = w.ToUpper(),​ Lower = w.ToLower()};​
 +foreach (var ul in upperLowerWords) {
 +        Console.WriteLine("​Uppercase:​ {0}, Lowercase: {1}", ul.Upper, ul.Lower);
 +</​code>​
 +Otro...
 +<code csharp>
 +var productInfos =
 +        from p in products
 +        select new {p.ProductName,​ p.Category, Price = p.UnitPrice};​
 + ​foreach (var productInfo in productInfos) {
 +        Console.WriteLine("​{0} is in the category {1} and costs {2} per unit.",​ productInfo.ProductName,​ productInfo.Category,​ productInfo.Price);​
 +</​code>​
 +Otro...
 +<code csharp>
 +int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
 +var numsInPlace = numbers.Select((num,​ index) => new {Num = num, InPlace = (num == index)});
 +</​code>​
 +Otro... con asignación
 +<code csharp>
 + var orders =
 +        from c in customers,
 +                o in c.Orders,
 +                total = o.Total
 +        where total >= 2000.0M
 +        select new {c.CustomerID,​ o.OrderID, total};
 +</​code>​
 +==== Relación de tablas ====
 +<code csharp>
 +var orders =
 +        from c in customers
 +        where c.Region == "​WA"​
 +        from o in c.Orders
 +        where o.OrderDate >= cutoffDate
 +        select new {c.CustomerID,​ o.OrderID};
 +</​code>​
 +
 +==== Ordenación ====
 +=== Orderby ===
 +<code csharp>
 +var sortedWords =
 +        from w in words
 +        orderby w.Length
 +        select w;
 +</​code>​
 +
 +=== Orderby Descending ===
 +<code csharp>
 +var sortedWords =
 +        from w in words
 +        orderby w.Length descending
 +        select w;
 +</​code>​
 +
 +=== Cambiar el orden ===
 +<code csharp>
 +var reversedIDigits = (
 +        from d in digits
 +        where d[1] == '​i'​
 +        select d)
 +        .Reverse();
 +</​code>​
 +
 +==== Contar elementos ====
 +
 +=== Count ===
 +<code csharp>
 +int[] factors = { 2, 2, 3, 5, 5 };
 +int uniqueFactors = factors.Distinct().Count(); ​
 +</​code>​
 +Devolvería 3
 +=== Contar los impares ===
 +
 +<code csharp>
 +int oddNumbers = numbers.Count(n => n % 2 == 1); 
 +</​code>​
 +=== Contar los carácteres de todas las palabras ===
 +<code csharp>
 +string[] words = { "​cherry",​ "​apple",​ "​blueberry"​ };
 +double totalChars = words.Sum(w => w.Length);
 +</​code>​
 +==== Concatenación de resultados ====
 +<code csharp>
 +var customerNames =
 +        from c in customers
 +        select c.CompanyName;​
 +var productNames =
 +        from p in products
 +        select p.ProductName;​
 +var allNames = customerNames.Concat(productNames);​
 +</​code>​
 +==== Selección de elementos ====
 +=== El primero ===
 +<code csharp>
 +Product product12 = (
 +        from p in products
 +        where p.ProductID == 12
 +        select p )
 +        .First();
 +</​code>​
 +=== El cuarto ===
 +<code csharp>
 +int fourthLowNum = (
 +        from n in numbers
 +        where n < 5
 +        select n )
 +        .ElementAt(3);​
 +</​code>​
 +
 +
 +===== Nuevas funciones =====
 +==== Range ====
 +Generación de los números de 100 a 150:
 +<code csharp>
 +from n in Sequence.Range(100,​ 50) 
 +</​code>​
 +==== Repeat ====
 +Repetición del número 7, 10 veces:
 +<code csharp>
 +var numbers = Sequence.Repeat(7,​ 10); 
 +</​code>​
 +
 +==== Distinct ====
 +Coge sólo uno, esquivando los elementos duplicados
 +<code csharp>
 +var categoryNames = (
 +        from p in products
 +        select p.Category)
 +        .Distinct();​
 +</​code>​
 +==== Union ====
 +Une dos listas del mismo tipo
 +<code csharp>
 +var uniqueNumbers = numbersA.Union(numbersB);​
 +</​code>​
 +
 +==== Intersect ====
 +Coge los elementos que se repiten en las dos listas
 +<code csharp>
 +var commonNumbers = numbersA.Intersect(numbersB);​
 +</​code>​
 +==== Except ====
 +Coge los elementos de la primera lista que no esten en la segunda
 +<code csharp>
 +IEnumerable<​int>​ aOnlyNumbers = numbersA.Except(numbersB);​
 +</​code>​
 +==== Take ====
 +Coge los primeros valores
 +<code csharp>
 +var first3Numbers = numbers.Take(3);​
 +</​code>​
 +<code csharp>
 +var first3WAOrders = (
 +                from c in customers
 +                from o in c.Orders
 +                where c.Region == "​WA"​
 +                select new {c.CustomerID,​ o.OrderID, o.OrderDate} )
 +                .Take(3);
 +</​code>​
 +
 +
 +==== Skip ====
 +Coge los últimos números saltandose los indicados
 +<code csharp>
 +var allButFirst4Numbers = numbers.Skip(4);​
 +</​code>​
 +=== Combinación de skip y take ===
 +<code csharp>
 +query.Skip(30).Take(10)
 +</​code>​
 +
 +
 +
 +===== Otros =====
 +
 +
 +==== let ====
 +La clausula ''​let''​ permite crear una variable dentro del ámbito de la query y utilizarla en la condición. ​
 +
 +<code csharp>
 +var lArrivals = from a in db.PIU_ARRIVALS
 +                let t = (DateTime.Now - a.updatedLocalTime)
 +                where (t.Seconds > seconds)
 +                select a;
 +</​code>​
 +... O ...
 +<code csharp>
 +from car in root.Elements("​car"​)
 +let profiles =
 +  from profile in car.Elements("​profile"​)
 +  select new {
 +    Name = profile.Attribute("​name"​).Value,​
 +    Value = profile.Attribute("​value"​).Value
 +  }
 +let supports =
 +  from support in car.Elements("​support"​)
 +  select new {
 +    Name = support.Attribute("​name"​).Value,​
 +    Value = support.Attribute("​value"​).Value
 +  }
 +select new Car {
 +  Name = car.Attribute("​name"​).Value,​
 +  Vendor = profiles.Single(prof => prof.Name == "​Vendor"​).Value,​
 +  Model = profiles.Single(prof => prof.Name == "​Model"​).Value,​
 +  Doors = int.Parse(profiles.Single(prof => prof.Name == "​Doors"​).Value),​
 +  RacingSupport = supports.Single(sup => sup.Name == "​Racing"​).Value == "​yes"​
 +};
 +</​code>​
 +
 +
 +
 +
 +===== Ejemplos =====
 +=== Ejemplo 1 ===
 +SQL:
 +<code sql>
 +SELECT SAE_LINEASPIENPANELINFO.INUMEROORDEN,​ SAE_LINEASPIENPANELINFO.SNOMBRELINEA,​ SAE_LINEASPIENPANELINFO.SNOMBREDESTINO, ​
 +            SAE_LINEASPIENPANELINFO.IIDLINEA,​ SAE_LINEASPIENPANELINFO.IIDTRAYECTO,​ SAE_LINEASPIENPANELINFO.IIDPARADA
 +FROM SAE_LINEASPIENPANELINFO,​ SAE_CONFBIENPROGRAMADAS
 +WHERE SAE_LINEASPIENPANELINFO.IIDPARADA = {0} AND SAE_LINEASPIENPANELINFO.IIDPANELINFO = {1} 
 +            AND SAE_CONFBIENPROGRAMADAS.IIDCONFLINEASACTUAL = SAE_LINEASPIENPANELINFO.IIDCONFIGURACIONLINEASPI ​
 +            AND SAE_CONFBIENPROGRAMADAS.IIDPANELINFO = {1}
 +ORDER BY SAE_LINEASPIENPANELINFO.INUMEROORDEN
 +</​code>​
 +LINQ:
 +<code csharp>
 +var dades = from linies in dbdc.SAE_LINEASPIENPANELINFO
 +            from conf in dbdc.SAE_CONFBIENPROGRAMADAS
 +            orderby linies.INUMEROORDEN
 +            where ((linies.IIDPARADA == p.IIDPARADA) &&
 +                (linies.IIDPANELINFO == codi) &&
 +                (conf.IIDCONFLINEASACTUAL == linies.IIDCONFIGURACIONLINEASPI) && ​
 +                (conf.IIDPANELINFO == codi))
 +            select new 
 +            {
 +                INUMEROORDEN = linies.INUMEROORDEN,​
 +                SNOMBRELINEA = linies.SNOMBRELINEA,​
 +                SNOMBREDESTINO = linies.SNOMBREDESTINO,​
 +                IIDLINEA = linies.IIDLINEA,​
 +                IIDTRAYECTO = linies.IIDTRAYECTO,​
 +                IIDPARADA = linies.IIDPARADA
 +            };
 +</​code>​
 +=== Ejemplo 2 (combinación) ===
 +Esto...
 +<​code>​
 +var id_paradas = (from pt in db.SAE_PARADASTRAYECTO
 +                       where (pt.IIDLINEA == idLinia)
 +                       ​select pt.IIDPARADA.GetValueOrDefault(-1)).Distinct();​
 +
 +return (from p in db.SAE_PARADAS
 +        from id in id_paradas
 +        where (p.IIDPARADA == id)
 +        select p).ToList();​
 +</​code>​
 +Es igual a...
 +<​code>​
 +return (from p in db.SAE_PARADAS
 +        from id in ((from pt in db.SAE_PARADASTRAYECTO
 +                       where (pt.IIDLINEA == idLinia)
 +                       ​select pt.IIDPARADA.GetValueOrDefault(-1)).Distinct())
 +        where (p.IIDPARADA == id)
 +        select p).ToList();​
 +</​code>​
 +=== Ejemplo 3 (NOT IN) ===
 +<​code>​
 +var query =
 +    from c in dc.Customers
 +    where !(from o in dc.Orders
 +            select o.CustomerID)
 +           ​.Contains(c.CustomerID)
 +    select c;
 +foreach (var c in query) Console.WriteLine( c );
 +</​code>​
 +=== Ejemplo 4 (FindAll y ForEach) ===
 +<​code>​
 +static void DisplayInstalledApplications2()
 +{
 +  string registryKey =
 +    @"​SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";​
 +
 +  using (Microsoft.Win32.RegistryKey key = 
 +    Registry.LocalMachine.OpenSubKey(registryKey))
 +  {
 +    (from a in key.GetSubKeyNames()
 +      let r = key.OpenSubKey(a)
 +      select new
 +      {
 +        Application = r.GetValue("​DisplayName"​)
 +      }).ToList()
 +      .FindAll(c => c.Application != null)
 +      .ForEach(c => Console.WriteLine(c.Application));​
 +  }
 +}
 +</​code>​
 +=== Cálculo del tamaño de un directorio ===
 +<code csharp>
 +static long DirectorySize(DirectoryInfo dInfo, bool includeSubDir) {
 +  // Enumerate all the files
 +  long totalSize = dInfo.EnumerateFiles()
 +    .Sum(file => file.Length);​
 +  // If Subdirectories are to be included
 +  if (includeSubDir)
 +  {
 +    // Enumerate all sub-directories
 +    totalSize += dInfo.EnumerateDirectories()
 +      .Sum(dir => DirectorySize(dir,​ true));
 +  }
 +  return totalSize;
 +}
 +</​code>​
 +
 +===== Notas =====
 +  * En las querys LINQ podemos ver el código SQL generado; si se debuga se puede ver el comando sql en la variable a la que se le ha asignado dicha query.
 +  * El resultado de una sentencia LINQ puede ser asignada a un ''​DataSource''​ de un ''​GridView''​. Luego tendremos que llamar al método ''​DataBind''​ para que se muestren.
fw/othersnet/linq.1237714653.txt.gz · Última modificación: 2020/05/09 09:24 (editor externo)