Sök…


Anmärkningar

LINQ är en uppsättning funktioner som introduceras i .NET Framework version 3.5 som överbryggar klyftan mellan objektens värld och datavärlden.

Traditionellt uttrycks frågor mot data som enkla strängar utan typkontroll vid sammanställningstid eller IntelliSense-support. Dessutom måste du lära dig ett annat frågespråk för varje typ av datakälla: SQL-databaser, XML-dokument, olika webbtjänster och så vidare. LINQ gör en fråga till en förstklassig språkkonstruktion i C # och Visual Basic. Du skriver frågor mot starkt typade samlingar av objekt med hjälp av språkord och kända operatörer.

Uppstart

LINQ kräver. NET 3.5 eller högre (eller .NET 2.0 med LINQBridge ).

Lägg till en referens till System.Core , om den inte har lagts till ännu.

Överst i filen, importera namnområdet:

  • C #
  using System;
  using System.Linq;
  • VB.NET
  Imports System.Linq

De olika går med i LINQ

I följande exempel använder vi följande prover:

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,
  },
};

INRE KOPPLING

Frågesyntax

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();

Metodsyntax

var joined = Products.Join(Orders, p => p.ProductId, 
                                   o => o.OrderId, 
                                     => new 
                                    { 
                                      OrderId   = o.OrderId, 
                                      ProductId = p.ProductId, 
                                      Name      = p.Name 
                                    })
                     .ToList();

Resultat:

{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" }

Vänster yttre medlem

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();

Resultat:

{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" },
{ NULL, 3, "Book nr 3" }

KRÄSS GÅ MED

var joined = (from p in Products
              from o in Orders
              select new
              {
                o.OrderId,
                p.ProductId,
                p.Name
              }).ToList();

Resultat:

{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" },
{ NULL, 3, "Book nr 3" },
{ 4, NULL, NULL }

GRUPPGÅRD

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();

Orders innehåller nu ett IEnumerable<Order> med alla länkade order.

Resultat:

{ 1, "Book nr 1", Orders = { 1, 2 } },
{ 2, "Book nr 2", Orders = { 3 } },
{ 3, "Book nr 3", Orders = { } },

Hur man går med på flera villkor

När du går med på ett enda villkor kan du använda:

join o in Orders 
  on p.ProductId equals o.ProductId

När du går med på flera använder du:

join o in Orders 
  on new { p.ProductId, p.CategoryId } equals new { o.ProductId, o.CategoryId }

Se till att båda anonyma objekt har samma egenskaper, och i VB.NET måste de vara markerade Key , även om VB.NET tillåter flera Equals klausuler separerade med And :

Join o In Orders 
  On p.ProductId Equals o.ProductId And p.CategoryId Equals o.CategoryId

Frågesyntax och metatsyntax

Frågesyntax och metatsyntax är semantiskt identiska, men många tycker att syntax för frågan är enklare och lättare att läsa. Låt oss säga att vi måste hämta alla jämna objekt som beställts i stigande ordning från en samling nummer.

C #:

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)

Kom ihåg att vissa frågor måste uttryckas som metodsamtal. Du måste till exempel använda ett metodsamtal för att uttrycka en fråga som hämtar antalet element som matchar ett angivet tillstånd. Du måste också använda ett metodsamtal för en fråga som hämtar det element som har det maximala värdet i en källsekvens. Så det kan vara en fördel med att använda metatsyntax för att göra koden mer konsekvent. Men du kan naturligtvis alltid använda metoden efter ett syntaxsamtal:

C #:

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();

LINQ-metoder och IEantal vs IQueryable

LINQ-förlängningsmetoder på IEnumerable<T> tar faktiska metoder 1 , oavsett om anonyma metoder:

//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);

eller namngivna metoder (metoder som uttryckligen definieras som en del av en klass):

//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

I teorin är det möjligt att analysera metodens IL , ta reda på vad metoden försöker göra och tillämpa metodens logik på alla underliggande datakällor, inte bara föremål i minnet. Men att analysera IL är inte för svag hjärta.


Lyckligtvis tillhandahåller .NET IQueryable<T> -gränssnittet och förlängningsmetoderna på System.Linq.Queryable för detta scenario. Dessa förlängningsmetoder tar ett uttrycksträd - en datastruktur som representerar kod - istället för en faktisk metod, som LINQ-leverantören sedan kan analysera 2 och konvertera till ett mer lämpligt formulär för att fråga den underliggande datakällan. Till exempel:

//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)

Om (till exempel) denna fråga är mot en SQL-databas, kan leverantören konvertera detta uttryck till följande SQL-sats:

SELECT *
FROM Persons
WHERE LastName LIKE N'A%'

och kör det mot datakällan.

Å andra sidan, om frågan strider mot ett REST-API, kan leverantören konvertera samma uttryck till ett API-samtal:

http://www.example.com/person?filtervalue=A&filtertype=startswith&fieldname=lastname

Det finns två primära fördelar med att skräddarsy en dataförfrågan baserad på ett uttryck (i motsats till att ladda hela samlingen i minnet och fråga lokalt):

  • Den underliggande datakällan kan ofta fråga mer effektivt. Till exempel kan det mycket väl finnas ett index på LastName . Att ladda objekt i lokalt minne och fråga i minnet förlorar den effektiviteten.
  • Uppgifterna kan formas och minskas innan de överförs. I det här fallet behöver databasen / webbtjänsten bara returnera matchningsdata, i motsats till hela uppsättningen personer tillgängliga från datakällan.

anteckningar
1. Tekniskt tar de inte metoder, utan delegerar till exempel instanser som pekar på metoder . Men denna distinktion är irrelevant här.
2. Detta är orsaken till fel som " LINQ to Entities känner inte igen metoden 'System.String ToString ()' och denna metod kan inte översättas till ett butiksuttryck. ". LINQ-leverantören (i detta fall leverantören av Entity Framework) vet inte hur man ska analysera och översätta ett samtal till ToString till motsvarande SQL.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow