linq Tutorial
Empezando con linq
Buscar..
Observaciones
LINQ es un conjunto de características introducidas en .NET Framework versión 3.5 que cierra la brecha entre el mundo de los objetos y el mundo de los datos.
Tradicionalmente, las consultas contra los datos se expresan como cadenas simples sin verificación de tipo en tiempo de compilación o soporte de IntelliSense. Además, debe aprender un lenguaje de consulta diferente para cada tipo de fuente de datos: bases de datos SQL, documentos XML, diversos servicios web, etc. LINQ realiza una consulta en una construcción de lenguaje de primera clase en C # y Visual Basic. Usted escribe consultas contra colecciones de objetos fuertemente tipadas usando palabras clave de lenguaje y operadores familiares.
Preparar
LINQ requiere .NET 3.5 o superior (o .NET 2.0 usando LINQBridge ).
Agregue una referencia a System.Core , si aún no se ha agregado.
En la parte superior del archivo, importe el espacio de nombres:
- DO#
using System;
using System.Linq;
- VB.NET
Imports System.Linq
Las diferentes uniones en LINQ.
En los siguientes ejemplos, usaremos los siguientes ejemplos:
List<Product> Products = new List<Product>()
{
new Product()
{
ProductId = 1,
Name = "Book nr 1",
Price = 25
},
new Product()
{
ProductId = 2,
Name = "Book nr 2",
Price = 15
},
new Product()
{
ProductId = 3,
Name = "Book nr 3",
Price = 20
},
};
List<Order> Orders = new List<Order>()
{
new Order()
{
OrderId = 1,
ProductId = 1,
},
new Order()
{
OrderId = 2,
ProductId = 1,
},
new Order()
{
OrderId = 3,
ProductId = 2,
},
new Order()
{
OrderId = 4,
ProductId = NULL,
},
};
UNIR INTERNAMENTE
Sintaxis de consulta
var joined = (from p in Products
join o in Orders on p.ProductId equals o.ProductId
select new
{
o.OrderId,
p.ProductId,
p.Name
}).ToList();
Sintaxis del método
var joined = Products.Join(Orders, p => p.ProductId,
o => o.OrderId,
=> new
{
OrderId = o.OrderId,
ProductId = p.ProductId,
Name = p.Name
})
.ToList();
Resultado:
{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" }
IZQUIERDA COMBINACIÓN EXTERNA
var joined = (from p in Products
join o in Orders on p.ProductId equals o.ProductId into g
from lj in g.DefaultIfEmpty()
select new
{
//For the empty records in lj, OrderId would be NULL
OrderId = (int?)lj.OrderId,
p.ProductId,
p.Name
}).ToList();
Resultado:
{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" },
{ NULL, 3, "Book nr 3" }
Unirse a la cruz
var joined = (from p in Products
from o in Orders
select new
{
o.OrderId,
p.ProductId,
p.Name
}).ToList();
Resultado:
{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" },
{ NULL, 3, "Book nr 3" },
{ 4, NULL, NULL }
Unirse al grupo
var joined = (from p in Products
join o in Orders on p.ProductId equals o.ProductId
into t
select new
{
p.ProductId,
p.Name,
Orders = t
}).ToList();
Las Orders
Propiedad ahora contienen un IEnumerable<Order>
con todas las Órdenes vinculadas.
Resultado:
{ 1, "Book nr 1", Orders = { 1, 2 } },
{ 2, "Book nr 2", Orders = { 3 } },
{ 3, "Book nr 3", Orders = { } },
Cómo unirse en múltiples condiciones
Al unirse en una sola condición, puede utilizar:
join o in Orders
on p.ProductId equals o.ProductId
Al unir en múltiples, use:
join o in Orders
on new { p.ProductId, p.CategoryId } equals new { o.ProductId, o.CategoryId }
Asegúrese de que ambos objetos anónimos tengan las mismas propiedades, y en VB.NET, deben estar marcados como Key
, aunque VB.NET permite varias cláusulas de Equals
separadas por And
:
Join o In Orders
On p.ProductId Equals o.ProductId And p.CategoryId Equals o.CategoryId
Sintaxis de consulta y sintaxis de método
La sintaxis de consulta y la sintaxis de método son semánticamente idénticas, pero muchas personas encuentran la sintaxis de consulta más sencilla y más fácil de leer. Digamos que necesitamos recuperar todos los artículos pares ordenados en orden ascendente de una colección de números.
DO#:
int[] numbers = { 0, 1, 2, 3, 4, 5, 6 };
// Query syntax:
IEnumerable<int> numQuery1 =
from num in numbers
where num % 2 == 0
orderby num
select num;
// Method syntax:
IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);
VB.NET:
Dim numbers() As Integer = { 0, 1, 2, 3, 4, 5, 6 }
' Query syntax: '
Dim numQuery1 = From num In numbers
Where num Mod 2 = 0
Select num
Order By num
' Method syntax: '
Dim numQuery2 = numbers.where(Function(num) num Mod 2 = 0).OrderBy(Function(num) num)
Recuerde que algunas consultas deben expresarse como llamadas de método. Por ejemplo, debe usar una llamada de método para expresar una consulta que recupera el número de elementos que coinciden con una condición específica. También debe usar una llamada de método para una consulta que recupera el elemento que tiene el valor máximo en una secuencia de origen. Entonces, eso podría ser una ventaja de usar la sintaxis de los métodos para hacer que el código sea más consistente. Sin embargo, por supuesto, siempre puede aplicar el método después de una llamada de sintaxis de consulta:
DO#:
int maxNum =
(from num in numbers
where num % 2 == 0
select num).Max();
VB.NET:
Dim maxNum =
(From num In numbers
Where num Mod 2 = 0
Select num).Max();
Métodos LINQ, y IEnumerable vs IQueryable
Los métodos de extensión LINQ en IEnumerable<T>
toman los métodos reales 1 , ya sean métodos anónimos:
//C#
Func<int,bool> fn = x => x > 3;
var list = new List<int>() {1,2,3,4,5,6};
var query = list.Where(fn);
'VB.NET
Dim fn = Function(x As Integer) x > 3
Dim list = New List From {1,2,3,4,5,6};
Dim query = list.Where(fn);
o métodos nombrados (métodos definidos explícitamente como parte de una clase):
//C#
class Program {
bool LessThan4(int x) {
return x < 4;
}
void Main() {
var list = new List<int>() {1,2,3,4,5,6};
var query = list.Where(LessThan4);
}
}
'VB.NET
Class Program
Function LessThan4(x As Integer) As Boolean
Return x < 4
End Function
Sub Main
Dim list = New List From {1,2,3,4,5,6};
Dim query = list.Where(AddressOf LessThan4)
End Sub
End Class
En teoría, es posible analizar el IL del método , averiguar qué está tratando de hacer el método y aplicar la lógica de ese método a cualquier fuente de datos subyacente, no solo a los objetos en la memoria. Pero el análisis de la IL no es para los débiles de corazón.
Afortunadamente, .NET proporciona la interfaz IQueryable<T>
y los métodos de extensión en System.Linq.Queryable
, para este escenario. Estos métodos de extensión tienen un árbol de expresión - una estructura de datos que representa código - en lugar de un método actual, que el proveedor de LINQ entonces puede analizar 2 y convertir a una forma más apropiada para la consulta de la fuente de datos subyacente. Por ejemplo:
//C#
IQueryable<Person> qry = PersonsSet();
// Since we're using a variable of type Expression<Func<Person,bool>>, the compiler
// generates an expression tree representing this code
Expression<Func<Person,bool>> expr = x => x.LastName.StartsWith("A");
// The same thing happens when we write the lambda expression directly in the call to
// Queryable.Where
qry = qry.Where(expr);
'VB.NET
Dim qry As IQueryable(Of Person) = PersonSet()
' Since we're using a variable of type Expression(Of Func(Of Person,Boolean)), the compiler
' generates an expression tree representing this code
Dim expr As Expression(Of Func(Of Person, Boolean)) = Function(x) x.LastName.StartsWith("A")
' The same thing happens when we write the lambda expression directly in the call to
' Queryable.Where
qry = qry.Where(expr)
Si (por ejemplo) esta consulta es contra una base de datos SQL, el proveedor podría convertir esta expresión a la siguiente declaración SQL:
SELECT *
FROM Persons
WHERE LastName LIKE N'A%'
y ejecutarlo contra la fuente de datos.
Por otro lado, si la consulta es contra una API REST, el proveedor podría convertir la misma expresión en una llamada a la API:
http://www.example.com/person?filtervalue=A&filtertype=startswith&fieldname=lastname
Hay dos ventajas principales en la personalización de una solicitud de datos basada en una expresión (en lugar de cargar toda la colección en la memoria y realizar consultas locales):
- El origen de datos subyacente a menudo puede consultar de manera más eficiente. Por ejemplo, puede haber un índice en el
LastName
. Cargar los objetos en la memoria local y consultar en la memoria pierde esa eficiencia. - Los datos pueden ser conformados y reducidos antes de ser transferidos. En este caso, la base de datos / servicio web solo necesita devolver los datos coincidentes, a diferencia del conjunto completo de Personas disponibles desde la fuente de datos.
Notas
1. Técnicamente, no toman métodos, sino delegan instancias que apuntan a métodos . Sin embargo, esta distinción es irrelevante aquí.
2. Este es el motivo de errores como " LINQ to Entities no reconoce el método 'System.String ToString ()', y este método no se puede traducir a una expresión de tienda ". El proveedor de LINQ (en este caso, el proveedor de Entity Framework) no sabe cómo analizar y traducir una llamada a ToString
a un SQL equivalente.