EF Core ist geboren, He Sheng

Inhaltsverzeichnis

1. Wie kann IQueryable geboren werden, da IEnumerable geboren wurde?

Zweitens die verzögerte Ausführung von IQueryable

Drittens die Wiederverwendung von lQueryable

Viertens: EF Core-Paginierungsabfrage

Fünftens die zugrunde liegende Operation von IQueryable

1. Szenario 1: Die Methode muss Abfrageergebnisse zurückgeben

2. Szenario 2: Mehrere IQueryable-Traversal-Verschachtelungen


1. Wie kann IQueryable geboren werden, da IEnumerable geboren wurde?

        Wir wissen bereits, dass Sie Methoden wie „Where“ in LINQ verwenden können, um Zeilen für gewöhnliche Sammlungen auszuwählen. Der folgende C#-Code kann beispielsweise die Daten größer als 10 im int-Array extrahieren:

int[] nums = { 3,5,933,2,69,69,11 };
IEnumerable<int> items = nums.where(n => n > 10):

        Klicken Sie mit der rechten Maustaste auf die Where-Methode und dann auf die Schaltfläche [Gehe zur Definition]. Sie können sehen, dass die Erweiterungsmethode in der Enumerable-Klasse der hier aufgerufenen Where-Methode wie folgt deklariert ist.

IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,Func<TSource,bool> predicate);

        Wir können auch Methoden wie Where auf dem DbSet-Typ von EF Core aufrufen, um Daten zu filtern. Beispielsweise kann der folgende Code Bücher herausfiltern, deren Preis höher als 1,1 Yuan ist;

IQueryable<Book> books ctx.Books.Where(b => b.Price > 1.1 );

        Wenn wir uns die Deklaration der hier aufgerufenen Where-Methode ansehen, werden wir feststellen, dass es sich um eine in der Queryable-Klasse definierte Erweiterungsmethode handelt. Die Deklaration der Methode lautet wie folgt;

IQueryable<TSource> Where<TSource>(this IQueryable<TSource> sourceExpression<Func<TSource, bool>> predicate);

        Diese Where-Methode ist eine Erweiterungsmethode vom Typ IQueryable<TSource> und der Rückgabewert ist vom Typ IQueryabl<TSource>. IQueryable ist eigentlich eine Schnittstelle, die die IEnumerable-Schnittstelle erbt, wie unten gezeigt;

public interface IOuervable<out T> : IEnumerable<T>, IEnumerable, IQueryablel{}

        Die IQueryable-Schnittstelle wird von der IEnumerable-Schnittstelle geerbt; die Where-Methode in der Queryable-Klasse unterscheidet sich nicht von der Where-Methode in der Enumerable-Klasse, außer dass die Parameter und Rückgabewerttypen IQueryable sind. Warum hat Microsoft dann eine IQueryable-Schnittstelle und eine neue Where-Methode eingeführt?

        Bei gewöhnlichen Sammlungen filtert die Where-Methode jedes Datenelement im Speicher. Wenn EF Core auch alle Daten im Speicher filtert, müssen wir alle Daten in einer Datenbanktabelle hinzufügen. Im Speicher wird die Methode einzeln verarbeitet durch bedingte Beurteilung. Wenn die Datenmenge nicht groß ist, treten Leistungsprobleme auf. Daher muss die Where-Implementierung in EF Core über einen Mechanismus zur „Konvertierung von Where-Bedingungen in SOL-Anweisungen“ verfügen, damit die Datenfilterung auf dem Datenbankserver durchgeführt werden kann. Der Prozess der Verwendung von SOL-Anweisungen zur Vervollständigung der Datenüberprüfung auf dem Datenbankserver wird als „Serverauswertung“ bezeichnet. Der Prozess, bei dem zunächst Daten zum Speicher des Anwendungsprogramms hinzugefügt und dann die Datenfilterung im Speicher durchgeführt wird, wird als „Clientauswertung“ bezeichnet. Offensichtlich , denn In den meisten Fällen ist die Leistung der „Kundenbewertung“ relativ gering, und wir sollten versuchen, eine „Kundenbewertung“ zu vermeiden.

        Die in der Enumerable-Klasse für gewöhnliche Sammlungen definierten Where- und anderen Methoden sind „Client-Auswertungen“. Daher hat Microsoft den IQueryable-Typ erstellt und die Where- und andere Methoden ähnlich der Enumerable-Klasse in Queryable und anderen Klassen definiert. Die in Queryable definierte Where-Methode unterstützt die Konvertierung von LINQ-Abfragen in SQL-Anweisungen. Daher sollten wir bei Verwendung von EF Core versuchen, die IQueryable-Version der Methode aufzurufen, anstatt die IEnumerable-Version der Methode direkt aufzurufen, um eine „Client-Auswertung“ zu vermeiden.

        Gib ein Beispiel. Verwenden Sie den folgenden Code, um Bücher zu erhalten, deren Preis mehr als 1,1 Yuan beträgt.

IQueryable<Book> books = ctx.Books.Where(b => b.Price > 1.1);
foreach (var b in books.Where(b => b.price > 1.1))
{
Console.WriteLine($"Id={b.Id),Title={b.Title}"); 
}

        Die durch den obigen Code generierte SQL-Anweisung lautet wie folgt

SELECT [t].[Id],[t].[AuthorName],[t].[Price],[t].[PubTime], [t].[Title) FROM[T_Books] AS [t] WHERE [t].[Price] >1.1000000000000001E0

        Hier ist die „serverseitige Auswertung“, die von EF Core mithilfe von SQL-Anweisungen auf dem Datenbankserver durchgeführt wird. Da die Variable „books“ vom Typ „IQueryable<Book>“ ist, wird hier die Where-Methode der IQueryable-Version aufgerufen.

        Als Nächstes ändern wir den Code geringfügig, ändern den Typ der Books-Variablen von IQueryable<Book> in IEnumerable<Book> und nehmen keine Änderungen an anderen Codes vor, wie im Code gezeigt.

IEnumerablc<Book> books = ctx.Books;
foreach (var b in books,where(b => b.Price > 1.1))
{
Console.WriteLine($"Id={b.Id},Title={b.Title}"); 
}

Schauen wir uns die entsprechende generierte SQL-Anweisung wie folgt an:

SELECT[t].[Id],[t].[AuthorName],[t].[Price],[t].[PubTime], [t].[Title] FR[T_Books] AS [t]

        Dieses Mal lädt das Programm alle Daten in der T_Books-Tabelle in den Anwendungsspeicher und filtert dann die Daten im Speicher, was zur „Client-Bewertung“ wird. Da Bücher vom Typ IEnumerable <Book> sind, wird hier die Where-Methode der IEnumerable-Version aufgerufen.

        In der Queryable-Klasse ist nicht nur die Where-Methode definiert, sondern auch Select, OrderBy, GroupBy, Min und andere Methoden. Die Verwendung dieser Methoden ist fast dieselbe wie die der gleichnamigen Methode, die in der Enumerable-Klasse definiert ist . Der einzige Unterschied besteht darin, dass es sich bei beiden um „serverseitige Evaluierungsversionen“ handelt.

        Kurz gesagt, wenn wir EF Core verwenden, sollten wir unser Bestes geben, um eine „Client-Bewertung“ zu vermeiden. Wenn Sie IQueryable<>m verwenden können,
verwenden Sie IEnumerable<T> nicht direkt.

Zweitens die verzögerte Ausführung von IQueryable

        IQueryable bietet nicht nur die Funktion „serverseitige Auswertung“, sondern auch die Möglichkeit, die Ausführung zu verzögern. In diesem Abschnitt wird die verzögerte Ausführungsfunktion von IQueryable vorgestellt.

        Schreiben Sie Code, um Datenabfragen durchzuführen.

IQueryable<Book> books = ctx.Books.Where(b => b.Price > 1.1); 
Console.WriteLine(books) 

        Dieser Code fragt nur Bücher ab, deren Preis mehr als 11 Yuan beträgt, es gibt jedoch keine Traversal-Ausgabe für den Rückgabewert. Wir haben die vom Protokollausgabecode für TestDbContext ausgeführte SQL-Anweisung und das Protokollausgabeergebnis des obigen Programms aktiviert.

        Aus der Ausgabe der Protokollergebnisse ist ersichtlich, dass der obige Code die SQL-Anweisung nicht ausgeführt hat, wir aber eindeutig die Where-Methode ausgeführt haben, um die Daten zu filtern und abzufragen.

        Ändern Sie den Code und durchlaufen Sie die Abfrageergebnisse, wie unten gezeigt.

Console.writeLine("1,Where 之前");
IQueryable<Book> books = ctx.Books,Where(b->b,Price>1.1); 
Console.WriteLine("2, 遍历 IQueryable之前");
foreach (var b in books)
{
Console.WriteLine(b.Title + ":" + b.PubTime); 
}
Console.WriteLine("3,遍历IQueryable之后");

       Beobachten Sie die Protokollausgabe des obigen Programms. Bitte beachten Sie sorgfältig die Ausgabesequenz der SQL-Anweisung, „2. vor dem Durchlaufen von IQueryable“ und „3. nach dem Durchlaufen von IQueryable“ im Screenshot der obigen Ausgabeergebnisse. Gemäß dem Code in C# wird der Code mit dem Namen „Where“ vor „2. Vor dem Durchlaufen von IQueryabl“ ausgeführt, aber im Ausführungsergebnis wird die SQL-Anweisung nach „2. Vor dem Durchlaufen von IQueryable“ ausgeführt. Warum?

Tatsächlich stellt IQueryable lediglich „eine Abfrage dar, die auf dem Datenbankserver ausgeführt werden kann“, sie wird nicht sofort ausgeführt, sondern „kann ausgeführt werden“. Dies ist tatsächlich aus der englischen Bedeutung des IQueryable-Typnamens ersichtlich: „IQueryabla“ bedeutet „abfragbar“, was abgefragt werden kann, aber die Abfrage wird nicht ausgeführt und die Ausführung der Abfrage verzögert sich.

        Wann wird IQueryable die Abfrage ausführen? Ein Prinzip lautet: Für die IQueryable-Schnittstelle wird die Abfrage nicht ausgeführt, wenn die Methode „Nicht-sofortige Ausführung“ aufgerufen wird, und die Abfrage wird sofort ausgeführt, wenn die Methode „Sofortige Ausführung“ aufgerufen wird. Zusätzlich zum Durchlaufen von IQueryable-Operationen gibt es Methoden zur sofortigen Ausführung wie ToArray, ToList, Min, Max und Count; Methoden wie GroupE OrderBy, Include, Skip und Take sind Methoden zur nicht sofortigen Ausführung. Der einfache Weg, um zu beurteilen, ob eine Methode eine Methode zur sofortigen Ausführung ist, ist: Wenn der Rückgabewerttyp einer Methode vom Typ IQueryable ist, handelt es sich bei dieser Methode im Allgemeinen um eine Methode zur nicht sofortigen Ausführung, andernfalls handelt es sich bei dieser Methode um eine Methode zur sofortigen Ausführung.

        Warum implementiert EF Core einen so komplizierten Mechanismus wie „IQueryable verzögerte Ausführung“? Weil wir IQueryable verwenden können, um komplexe Abfragebedingungen vor der Ausführung der Abfrage zusammenzufügen. Der folgende Code definiert beispielsweise eine Methode, die verwendet wird, um passende Bücher basierend auf dem angegebenen Schlüsselwort „searchWords“ abzufragen. Wenn der Parameter „searchAll“ wahr ist, dann wird der Buchtitel oder der Name des Autors, der die angegebenen „searchWords“ enthält, abgeglichen, andernfalls stimmt nur das Buch überein title; wenn der Parameter „orderByPrice“ wahr ist, werden die Abfrageergebnisse nach Preis sortiert, andernfalls werden sie natürlich sortiert; der Parameter „upperPrice“ stellt die Preisgrenze dar, wie im folgenden Code gezeigt

void QueryBooks(string searchWords, bool searchAll, bool orderByPrice, double upperPrice
{
using TestDbContext ctx = new TestDbContext(); 
IQueryable<Book> books = ctx.Books.Where(b => b.Price <= upperPrice); 
if (searchAll) //匹配书名或作者名 
{
books = books.Where(b => b.Title.Contains(searchWords)II 
b.AuthorName.Contains(searchWords));
} 
else //只匹配书名 
{ 
books = books.Where(b => b.Title.Contains(searchWords));
}
if (orderlyPrice) //按照价格排序 
{
books = books.OrderBy(b => b.Price); 
}
foreach (Book b in books) 
{
Console.WriteLine($"ib.Id),{b.Titlo},(b.Price},(b.AuthorName}");
}
}

        Wir filtern das von ctx.Books.Where(b=>b.Price<=upperPrice) zurückgegebene IQueryable<Book>-Objekt weiter mithilfe von Where, OrderBy und anderen Methoden gemäß den vom Benutzer übergebenen Parametern, nur wenn foreach zum Durchlaufen von Büchern verwendet wird Abfrage ausführen

        Wir schreiben den folgenden Code, um die QueryBooks-Methode aufzurufen: 

QueryBooks("爱",true,true,30);

Sehen Sie sich die Protokollausgabe des Programms der vom obigen Code ausgeführten SQL-Anweisung an.

        Es ist ersichtlich, dass wir die SQL-Anweisung beim Spleißen von IQueryable nicht ausgeführt haben und die SQL-Anweisung nur beim Durchlaufen von IQueryable am Ende ausgeführt haben. Diese SQL-Anweisung hat die beiden von uns festgelegten Where-Filterbedingungen zu einer Where-Bedingung zusammengeführt. Die SQL-Anweisung enthält auch die von uns festgelegte Order By-Anweisung.

        Versuchen wir noch einmal, die QueryBooks-Methode aufzurufen

QueryBooks("爱",false,false,18);

Sehen Sie sich die Protokollausgabe des Programms für die vom obigen Code ausgeführte SQL-Anweisung an.

        Es ist ersichtlich, dass aufgrund der unterschiedlichen übergebenen Parameter das von uns gespleißte IQueryable unterschiedlich ist, sodass auch die SQL-Anweisung, die bei der endgültigen Ausführung der Abfrage generiert wird, unterschiedlich ist.

        Wenn Sie EF Core nicht verwenden, sondern SQL-Anweisungen verwenden, um die Logik des „Ausführens verschiedener SQL-Anweisungen gemäß unterschiedlichen Parametern“ zu implementieren, müssen wir SQL-Anweisungen manuell spleißen. Dieser Prozess ist sehr mühsam und EF Core führt „dynamisches Spleißen“ zum Generieren durch Abfragelogik" in sehr einfache Weise.

        Kurz gesagt stellt IOueryable eine Logik zum Abfragen von Daten in der Datenbank dar, und diese Abfrage ist eine verzögerte Abfrage. Wir können die Methode zur nicht sofortigen Ausführung aufrufen, um IQueryable Abfragelogik hinzuzufügen, und die SQL-Anweisung wird tatsächlich generiert, um die Abfrage auszuführen, wenn die Methode zur sofortigen Ausführung ausgeführt wird.

Drittens die Wiederverwendung von lQueryable

        IQueryable ist eine abzufragende Logik, sodass sie wiederverwendet werden kann, wie im folgenden Code gezeigt.

IQueryable<Book> books = ctx.Books.Where(b => b.Price >=8);
Console.WriteLine(books.Count());
Console.WriteLine(books.Max(b=> b.Price));
foreach(Book b in books.Where(b => b.PubTime.Year >2000))
{
Console.WriteLine(b.Title)i 
}

        Der obige Code erstellt zunächst ein IQueryable-Objekt, um Bücher abzurufen, deren Preis größer oder gleich 8 Yuan ist, ruft dann die Count-Methode auf, um das IQueryable-Objekt auszuführen und die Anzahl der Datenelemente abzurufen, die die Bedingungen erfüllen, und ruft dann die Max-Methode auf um das IQueryable-Objekt auszuführen, um den höchsten Preis zu erhalten, der die Bedingungen erfüllt. Schließlich wird die Where-Methode für die Variable „books“ aufgerufen, um Bücher, die nach 2000 veröffentlicht wurden, weiter zu filtern und abzurufen.

        Der obige Code generiert die folgende SQL-Anweisung:

SELECT COUNT(*) FROM [T_Books] AS [t] WHERE [t].[Price] >= 8.0E0;
SELECTMAX([t].[Price]) FROM [T_Books] AS [t] WHERE [t].[Price] >= 8.0E0;
SELECT[t].[Id],[t].[AuthorName],[t].[Price],[t].[PubTime], [t].[Title] FROM
[T_Books] AS [t]
WHERE([t].[Price] >= 8.0EO) AND (DATEPART(year, [t].[PubTime]) > 2000);

        Da Count, Max und foreach alle sofort ausgeführt werden, ist ersichtlich, dass die drei Operationen auf IQueryable jeweils die entsprechende Abfragelogik ausführen. Mit IQueryable können wir die zuvor generierte Abfragelogik wiederverwenden, die in der unten beschriebenen Paging-Abfrage verwendet wird.

Viertens: EF Core-Paginierungsabfrage

        Wenn die Datenbanktabelle viele Daten enthält, müssen wir beim Anzeigen der Abfrageergebnisse im Frontend normalerweise die Abfrageergebnisse auf Seiten anzeigen.

        Bei der Realisierung des Paging-Anzeigeeffekts muss das Programm die Methode zum Abrufen von Daten aus der Datenbanktabelle durch Paging implementieren. Beispielsweise zeigt jede Seite 10 Datenelemente an. Wenn wir die Daten auf der dritten Seite anzeigen möchten (Seitenzahl beginnt). Von 1) müssen wir die Daten von der 20. Seite erhalten. Die ersten 10 Datenelemente.

        Wir wissen, dass die Skip(n)-Methode verwendet werden kann, um „n Datenteile überspringen“ zu realisieren, und die Take(n)-Methode verwendet werden kann, um „bis zu n Datenteile zu übernehmen“ zu realisieren. Diese beiden Methoden können kombiniert werden um Daten in Seiten zu erhalten, z. B. Skip(3). Take(8) bedeutet „Bis zu 8 Daten ab der dritten abrufen“. Diese beiden Methoden werden auch in EF Core unterstützt.

        Bei der Implementierung von Paging müssen wir zur Anzeige der Seitenzahlenleiste die Gesamtzahl der Daten kennen, die die Bedingungen erfüllen. Sie können das Multiplexing von IQueryable verwenden, um die beiden Abfragevorgänge Daten-Paging-Abfrage und Abrufen der Gesamtzahl der Daten zu realisieren, die die Bedingungen erfüllen.

        Im Folgenden wird eine Methode gekapselt, um den Inhalt der n-ten Seite (Seitenzahl beginnt bei 1), deren Titel nicht „Zhang San“ enthält, auszugeben und die Gesamtzahl der Seiten auszugeben. Auf jeder Seite werden bis zu 5 Daten angezeigt, wie gezeigt im folgenden Code.

void OutputPage(int pageIndex, int pageSize)
{
using TestDbContext ctx = new TestDbContext(); 
IQueryable<Book> books =ctx.Books.Where(b =>lb.Title.Contains("张三")); 
long count = books.LongCount(); 
long pageCount = (long)Math.Ceiling(count *1.0 /pageSize); //页数//总条数
Console.WriteLine("页数:"+ pageCount);
var pagedBooks = books.Skip((pageIndex - 1) * pageSize).Take(pageSize) 
foreach (var b in pagedBooks)
{
Console.WriteLine(b.Id + "," + b.Title);
}
}

        Der pageIndex-Parameter der OutputPage-Methode stellt die Seitenzahl dar, und der pageSize-Parameter stellt die Seitengröße dar. In der OutputPage-Methode erstellen wir zunächst die Abfrageregelbücher und verwenden dann die LongCount-Methode, um die Gesamtzahl der Datenelemente zu ermitteln, die die Bedingungen erfüllen. Die Gesamtzahl der Datenseiten kann mit countx1÷pageSize berechnet werden. Da die letzte Seite möglicherweise nicht voll ist, verwenden wir die Deckenmethode, um die Gesamtzahl der Seiten vom Typ Integer zu ermitteln. Da die Seriennummer von pageIndex bei I beginnt, verwenden wir die Skip-Methode, um (pageIndex-1)x pageSize-Datenelemente zu überspringen und dann die meisten pageSize-Datenelemente abzurufen, um die richtigen Paging-Daten zu erhalten.

        Wir verwenden den Codetest, um die Daten der ersten Seite und der zweiten Seite auszugeben.

OutputPage(1,5);
Console.WriteLine("******"); 
OutputPage(2,5)

Fünftens die zugrunde liegende Operation von IQueryable

        In ADO.NET gibt es zwei Möglichkeiten, Datenbankabfrageergebnisse zu lesen: DataReader und DataTable. Wenn das Abfrageergebnis viele Daten enthält, lädt DataTable alle Daten gleichzeitig vom Datenbankserver in den Clientspeicher und DataReader liest Daten stapelweise vom Datenbankserver. Der Vorteil von DataReader besteht darin, dass die Speichernutzung des Clients gering ist. Der Nachteil besteht darin, dass ein langsamer Prozess des Durchlaufens, Lesens und Verarbeitens von Daten dazu führt, dass das Programm die Datenbankverbindung für längere Zeit belegt, was zu einer Reduzierung führt Die gleichzeitige Verbindungsfunktion des Datenbankservers. Der Vorteil von DataTable besteht darin, dass die Daten schnell in den Speicher des Clients geladen werden, sodass die Datenbankverbindung nicht lange belegt wird. Der Nachteil besteht darin, dass die Datenmenge groß ist , wird die Speichernutzung des Clients relativ groß sein.

        Wenn IQueryable Daten durchläuft und liest, verwendet es eine ähnliche Methode wie DataReader oder DataTable? Wir fügen Hunderttausende Daten in die T_Books-Tabelle ein und verwenden dann Code, um IQueryable zu durchlaufen.

IQueryable<Book> books = ctx.Books.Where(b=>b.Id>2);
foreach (var b in books) 
{
Console.WriteLine(b.Id +"," + b.Title):
}

        Wenn wir während der Traversal-Ausführung den SQL Server-Server herunterfahren oder den Server vom Netzwerk trennen, geht das Programm schief, was bedeutet, dass IQueryable die Abfrageergebnisse auf ähnliche Weise wie DataReader liest. Tatsächlich besteht das Durchlaufen des IQueryable-p-Teils darin, DataReader aufzurufen, um Daten zu lesen. Daher muss beim Durchlaufen von IQueryable eine Datenbankverbindung belegt werden.

        Wenn Sie alle Daten gleichzeitig in den Clientspeicher einlesen müssen, können Sie Methoden wie ToArray, ToArrayAsync, ToList und ToListAsync von IQueryable verwenden. Lesen Sie, wie im folgenden Code gezeigt, die ersten 500.000 Daten, lesen Sie dann mit ToListAsync die Abfrageergebnisse auf einmal in den Speicher und durchlaufen Sie dann die Ausgabedaten.

var books = await ctx.Books.Take(500000).ToListAsyne();
foreach (var b in books)
{
Console.WriteLine(b.Id + "," + b.Title):
}

        Wenn wir beim Durchlaufen der Daten den SQL Server-Server schließen oder das Servernetzwerk trennen, kann das Programm normal ausgeführt werden, was bedeutet, dass die ToListAsync-Methode die Abfrageergebnisse in den Clientspeicher geladen hat.

        Sofern das Durchlaufen von IQueryable und die Datenverarbeitung nicht zeitaufwändig sind, ist es im Allgemeinen nicht erforderlich, die Abfrageergebnisse auf einmal in den Speicher einzulesen. In den folgenden Szenarien ist es jedoch erforderlich, die Abfrageergebnisse gleichzeitig in den Speicher einzulesen.

1. Szenario 1: Die Methode muss Abfrageergebnisse zurückgeben

        Wenn die Methode Abfrageergebnisse zurückgeben und den Kontext in der Methode zerstören muss, kann die Methode IQueryable nicht zurückgeben. Implementieren Sie beispielsweise die im folgenden Code gezeigte Methode, um Bücher mit der ID>5 abzufragen, und geben Sie dann die Abfrageergebnisse zurück.

IQueryable<Book> QueryBooks()
{
using TestDbContext ctx = new TestDbContext(); 
return ctx.Books,Where(b=>b.Id>5);
}

        Rufen Sie dann diese Methode in Ihrem Code auf.

foreach(var b in QueryBooks())
{
Console.WriteLine(b.Title)
}

        Nachdem der obige Code ausgeführt wurde, löst das Programm die Ausnahme „Zugriff auf eine entsorgte Kontextinstanz nicht möglich“ aus, da das TestDbContext-Objekt in der QueryBooks-Methode zerstört wird und der Kontext beim Durchlaufen von IQueryable Daten aus der Datenbank laden muss, so das Programm meldet einen Fehler. Wenn es sich um die QueryBooks-Methode handelt, verwenden Sie ToList und andere Methoden, um die Daten auf einmal in den Speicher zu laden.

IEnumerable<Book> QueryBooks()
{
using TestDbContext ctx = new TestDbContext(); 
return ctx.Books.Where(b => b.Id > 5).ToArray();
}

2. Szenario 2: Mehrere IQueryable-Traversal-Verschachtelungen

        Beim Durchlaufen eines IQueryable müssen wir möglicherweise gleichzeitig ein anderes IQueryable durchqueren. Die unterste Ebene von IQueryable verwendet DataReader, um Abfrageergebnisse vom Datenbankserver zu lesen, und viele Datenbanken unterstützen nicht die gleichzeitige Ausführung mehrerer DataReader.

        Wir verwenden die SQL Server-Datenbank, um zwei IQueryable-Durchläufe gemeinsam zu implementieren, wie im folgenden Code gezeigt.

var books = ctx.Books.Where(b=>b.Id>1);
foreach (var b in books)
{
Console.WriteLine (b.Id + "," + b.Title); 
foreach(var a in etx.Authors) 
{
Console.WriteLine(a,Id);
}
}

        Wenn das obige Programm ausgeführt wird, meldet es den Fehler „Dieser Verbindung ist bereits ein offener DataReader zugeordnet, der zuerst geschlossen werden muss.“ Dieser Fehler liegt daran, dass zwei foreach-Schleifen IQueryable durchlaufen, was dazu führt, dass zwei DataReader gleichzeitig ausgeführt werden Zeit.

        Obwohl Sie „Mehrfache DataReader-Ausführung zulassen“ aktivieren können, indem Sie in der Verbindungszeichenfolge „utipleActiveResultSets=true“ festlegen, unterstützt nur SQLServer die Option „MultipleActiveResultSets“ und andere Datenbanken unterstützen sie möglicherweise nicht. Daher schlägt der Autor vor, das Problem zu lösen, indem „die Daten auf einmal in den Speicher geladen werden“, um eine der Schleifen zu transformieren. Ändern Sie beispielsweise einfach var Books=ctx.Books.Where(b=>b.Id>1) zu var Books = ctx .Books.Where
(b=>b.Id>1).ToList() reicht aus.

        Zusammenfassend lässt sich sagen, dass wir bei der täglichen Entwicklung IQueryable direkt durchlaufen können. Wenn die Methode jedoch Abfrageergebnisse zurückgeben oder mehrere Abfragen verschachtelt ausführen muss, muss die Methode zum gleichzeitigen Laden von Daten in den Speicher in Betracht gezogen werden. Natürlich sollten die Daten für eine einmalige Abfrage nicht zu groß sein um keinen übermäßigen Speicherverbrauch zu verursachen.

Supongo que te gusta

Origin blog.csdn.net/xxxcAxx/article/details/128460582
Recomendado
Clasificación