¡Esta es una revisión vieja del documento!
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:
IEnumerable<Person> list = lPerson.Where(p => p.firstName.StartsWith("A")); int maxAge = lPerson.Max(p => p.age); double avg = lPerson.Average(p => p.age);
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:
from elementos_a_consultar in lista select elementos_devueltos
Un ejemplo:
IEnumerable<Person> list = from p in lPerson select p;
También podemos agregar clausulas where y orderby:
IEnumerable<Person> list = from p in lPerson where p.firstName.StartsWith("A") orderby p.age select p;
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í:
IEnumerable<string> list = from p in lPerson where p.firstName.StartsWith("A") orderby p.age select p.firstName;
También podemos consultar los elementos relacionados o ordendar descendentemente:
IEnumerable<string> categories = from c in Categories where c.Products.Count > 5 orderby c.CategoryName descending select c.CategoryName;
Otro ejemplo sería el de devolver un objeto de una clase que no es la de los elementos de la lista:
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; }
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:
List<Category> categories = (from c in db.Categories where c.CategoryName select c).ToList();
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:
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);
var expensiveInStockProducts = from p in products where p.UnitsInStock > 0 && p.UnitPrice > 3.00M select p;
string[] digits = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; var shortDigits = digits.Where((digit, index) => digit.Length < index);
int[] numbers = { 5, 4, 1}; var numsPlusOne = from n in numbers select n + 1;
Devolvería 6 5 2
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];
Devolvería five, four, one…
Coger una agrupación y el tipo de agrupación que es:
var wordGroups = from w in words group w by w[0] into g select new { FirstLetter = g.Key, Words = g };
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 } } };
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);
Otro…
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);
Otro…
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; var numsInPlace = numbers.Select((num, index) => new {Num = num, InPlace = (num == index)});
Otro… con asignación
var orders = from c in customers, o in c.Orders, total = o.Total where total >= 2000.0M select new {c.CustomerID, o.OrderID, total};
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};
var sortedWords = from w in words orderby w.Length select w;
var sortedWords = from w in words orderby w.Length descending select w;
var reversedIDigits = ( from d in digits where d[1] == 'i' select d) .Reverse();
int[] factors = { 2, 2, 3, 5, 5 }; int uniqueFactors = factors.Distinct().Count();
Devolvería 3
int oddNumbers = numbers.Count(n => n % 2 == 1);
string[] words = { "cherry", "apple", "blueberry" }; double totalChars = words.Sum(w => w.Length);
var customerNames = from c in customers select c.CompanyName; var productNames = from p in products select p.ProductName; var allNames = customerNames.Concat(productNames);
Product product12 = ( from p in products where p.ProductID == 12 select p ) .First();
int fourthLowNum = ( from n in numbers where n < 5 select n ) .ElementAt(3);
Generación de los números de 100 a 150:
from n in Sequence.Range(100, 50)
Repetición del número 7, 10 veces:
var numbers = Sequence.Repeat(7, 10);
Coge sólo uno, esquivando los elementos duplicados
var categoryNames = ( from p in products select p.Category) .Distinct();
Une dos listas del mismo tipo
var uniqueNumbers = numbersA.Union(numbersB);
Coge los elementos que se repiten en las dos listas
var commonNumbers = numbersA.Intersect(numbersB);
Coge los elementos de la primera lista que no esten en la segunda
IEnumerable<int> aOnlyNumbers = numbersA.Except(numbersB);
Coge los primeros valores
var first3Numbers = numbers.Take(3);
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);
Coge los últimos números saltandose los indicados
var allButFirst4Numbers = numbers.Skip(4);
query.Skip(30).Take(10)
La clausula let permite crear una variable dentro del ámbito de la query y utilizarla en la condición.
var lArrivals = from a in db.PIU_ARRIVALS let t = (DateTime.Now - a.updatedLocalTime) where (t.Seconds > seconds) select a;
… O …
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" };
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
LINQ:
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 };
Esto…
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();
Es igual a…
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();
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 );
DataSource de un GridView. Luego tendremos que llamar al método DataBind para que se muestren.