Ich habe eine Repository-Klasse, die meinen LINQ in SQL Data Context umschließt. Die Repository-Klasse ist eine Geschäftsbereichsklasse, die die gesamte Datenebenenlogik (und das Caching usw.) enthält.
Hier ist meine Version 1 meiner Repo-Oberfläche.
public interface ILocationRepository
{
IList<Location> FindAll();
IList<Location> FindForState(State state);
IList<Location> FindForPostCode(string postCode);
}
Um das Paging für FindAll zu handhaben, überlege ich, ob IQueryable <ILocation> anstelle von IList verfügbar gemacht werden soll, um die Benutzeroberfläche für Umstände wie Paging zu vereinfachen.
Was sind die Vor- und Nachteile, um IQueryable aus dem Daten-Repo herauszustellen?
Jede Hilfe wird sehr geschätzt.
c#
.net
linq-to-sql
iqueryable
CVertex
quelle
quelle
IEnumerable<T>
im Repository oder in der BLL vorgesehen, da dies die Leistung beeinträchtigen kann, wenn Sie nicht darauf geachtet und viele foreach-Schleifen für dieselbe Liste erstellt haben. In diesem Fall werden SieGetEnumerator()
viele Male aufrufen .Antworten:
Die Profis; Zusammensetzbarkeit:
Die Nachteile; Nichtprüfbarkeit:
IQueryable<T>
, dass sie zusammensetzbar sind, werden nicht zusammensetzbare Implementierungen ausgeschlossen - oder Sie werden gezwungen, einen eigenen Abfrageanbieter für sie zu schreibenFür Stabilität, habe ich genommen nicht auszusetzen
IQueryable<T>
oderExpression<...>
auf meine Repositories. Dies bedeutet, dass ich weiß, wie sich das Repository verhält, und dass meine oberen Ebenen Mocks verwenden können, ohne sich Sorgen machen zu müssen, ob das eigentliche Repository dies unterstützt. (Erzwingen von Integrationstests).Ich benutze immer noch
IQueryable<T>
etc im Repository - aber nicht über die Grenze. Ich habe hier einige weitere Gedanken zu diesem Thema veröffentlicht . Es ist genauso einfach, Paging-Parameter in die Repository-Oberfläche einzufügen. Sie können sogar Erweiterungsmethoden (auf der Schnittstelle) verwenden, um optionale Paging-Parameter hinzuzufügen , sodass die konkreten Klassen nur eine Methode implementieren müssen, dem Aufrufer jedoch möglicherweise 2 oder 3 Überladungen zur Verfügung stehen.quelle
IEnumerable<T>
wäre OK - aber hauptsächlich für große Datenmengen. Für reguläre Abfragen würde ich eine geschlossene Menge (Array / Liste / usw.) bevorzugen. Insbesondere verwende ich momentan MVC und möchte, dass der Controller alle DatenIEnumerable<T>
normalerweise mit verzögerter Ausführung verwendet wird). Wenn das Repo IList <T> (oder ähnliches) zurückgibt, wissen Sie, dass Sie die Daten haben.Assert.IsTrue(result.Any())
Wie in der vorherigen Antwort erwähnt, können Anrufer durch das Offenlegen von IQueryable mit IQueryable selbst spielen, was gefährlich ist oder werden kann.
Die erste Aufgabe der Geschäftslogik besteht darin, die Integrität Ihrer Datenbank aufrechtzuerhalten.
Sie können IList weiterhin verfügbar machen und Ihre Parameter wie folgt ändern: So machen wir ...
public interface ILocationRepository { IList<Location> FindAll(int start, int size); IList<Location> FindForState(State state, int start, int size); IList<Location> FindForPostCode(string postCode, int start, int size); }
Wenn Größe == -1, dann geben Sie alle ...
Alternativer Weg...
Wenn Sie IQueryable weiterhin zurückgeben möchten, können Sie IQueryable of List in Ihren Funktionen zurückgeben. Zum Beispiel ...
public class MyRepository { IQueryable<Location> FindAll() { List<Location> myLocations = ....; return myLocations.AsQueryable<Location>; // here Query can only be applied on this // subset, not directly to the database } }
Die erste Methode hat einen Vorteil gegenüber dem Speicher, da Sie weniger Daten als alle zurückgeben.
quelle
AsQueryable
, ehrlich zu sein. Ich bin mir nicht mal sicher, warum es existiert. Es verwandelt Ihre Liste nicht plötzlich in eine IQueryable und ermöglicht es Ihnen, Ausdrucksbäume zu erstellen, die an Ihren Datenspeicher gesendet werden. Worum geht es also?AsQueryable
ist nützlich, wenn Sie eine nicht generische DateiIEnumerable
von einer Legacy-API erhalten.Ich empfehle
IEnumerable
stattdessen zu verwendenIList
, damit haben Sie mehr Flexibilität.Auf diese Weise können Sie von Db nur den Teil der Daten abrufen, den Sie wirklich verwenden werden, ohne dass zusätzliche Arbeit in Ihrem Repository geleistet wird.
Stichprobe:
// Repository public interface IRepository { IEnumerable<Location> GetLocations(); } // Controller public ActionResult Locations(int? page) { return View(repository.GetLocations().AsPagination(page ?? 1, 10); }
Welches ist super sauber und einfach.
quelle
GetRecords(int page, int itemsPerPage)
. Anstatt das Paging an die Controller weiterzuleiten.