LINQ-NHibernate - die Auswahl von nur wenigen Feldern (einschließlich Sammlung) für ein Komplexes Objekt
Ich bin mit Fluent NHibernate in einem meiner Projekte (und ASP.NET MVC-Anwendung), mit LINQ-Abfragen, um die Daten (unter Verwendung des LINQ to NHibernate Bibliotheken).
Den objet Namen geändert zum Schutz der unschuldigen.
Sagen wir, ich habe die folgenden Klassen Foo, Bar, Baz, und die entsprechenden Tabellen in der Datenbank (MySQL).
Foo hat eine viele-zu-viele-Beziehung mit sowohl Bar (Tabelle "FooBar") und Baz (Tabelle "FooBaz"), definiert in der Fluent-mappings. Als solche, die Klassen-Schnittstelle ist wie folgt definiert:
public class Foo {
public virtual int id { get; set; }
public virtual string name { get; set; }
public virtual string email { get; set; }
public virtual IList<Bar> bars { get; set; }
public virtual IList<Baz> bazes { get; set; }
}
Dies ist ein ziemlich standard-Klasse. Wir können sehen, dass ein Foo-Objekt wird eine Liste von bars und bazes.
Das problem kommt, wenn Sie versuchen zu tun, eine LINQ-Abfrage.
Mache ich, wenn ich eine einfache Abfrage wie diese, funktioniert es einwandfrei (die where-Klausel ist unwichtig) :
var foos = from foo in session.Linq<Foo>()
where email.equals("[email protected]")
select foo;
IList<Foo> listFoos = foos.ToList();
Dieser gibt eine Liste von Foos, mit allen gefüllten Feldern (id, name, E-Mail, bars, bazes). log4net zeigt, dass NHibernate führt separate Abfragen für die Sammlungen.
Entsteht das problem, wenn ich laden will nur einige Felder. Ich könnte zum Beispiel möchten, laden Sie nur noch die bars in der Abfrage, aber nicht die bazes.
Diese Abfrage kompiliert wird, aber erzeugt einen Fehler zur Laufzeit:
var foos = from foo in session.Linq<Foo>()
where email.equals("[email protected]")
select new Foo()
{
id = foo.id,
name = foo.name,
email = foo.email,
bars = foo.bars
};
IList<Foo> listFoos = foos.ToList();
Den Fehler den ich bekomme, ist etwas entlang der Linien von einem array-index out of bounds exception. Der stack-trace zeigt einige Methoden, Bezeichnungen die im Zusammenhang der Sammlung Handhabung von LINQ-NHibernate-Seite, aber sonst nichts. Die Abfrage berichtet von log4net zeigt keine Anzeichen einer Abfrage auf Balken, was bedeutet, dass ein Fehler abgefangen wurde, bevor es die Zeit zum ausführen der Abfrage wählen Sie die bars.
Hatte noch jemand diese Art von problem vor? Wie hast du es lösen? Ich will nicht zu haben, wählen Sie alle Objekte jedesmal, wenn ich öffnen Sie eine web-Seite in meiner Bewerbung!
Danke!
Edit: hier ist der stacktrace, wie gewünscht.
System.IndexOutOfRangeException: L'index se trouve en dehors des limites du tableau. (read: "Index is out of bounds for the array.")
[IndexOutOfRangeException: L'index se trouve en dehors des limites du tableau.]
NHibernate.Transform.TypeSafeConstructorMemberInitResultTransformer.InvokeMemberInitExpression(MemberInitExpression expression, Object[] args, Int32& argumentCount) +404
NHibernate.Transform.TypeSafeConstructorMemberInitResultTransformer.TransformTuple(Object[] tuple, String[] aliases) +150
[QueryException: could not instantiate: Foo]
NHibernate.Transform.TypeSafeConstructorMemberInitResultTransformer.TransformTuple(Object[] tuple, String[] aliases) +265
NHibernate.Loader.Criteria.CriteriaLoader.GetResultColumnOrRow(Object[] row, IResultTransformer resultTransformer, IDataReader rs, ISessionImplementor session) +171
NHibernate.Loader.Loader.GetRowFromResultSet(IDataReader resultSet, ISessionImplementor session, QueryParameters queryParameters, LockMode[] lockModeArray, EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, Boolean returnProxies) +330
NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) +704
NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) +70
NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters) +111
NHibernate.Loader.Loader.ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters) +18
NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IType[] resultTypes) +79
NHibernate.Impl.SessionImpl.List(CriteriaImpl criteria, IList results) +407
NHibernate.Impl.CriteriaImpl.List(IList results) +41
NHibernate.Impl.CriteriaImpl.List() +35
NHibernate.Linq.<GetEnumerator>d__0.MoveNext() +71
System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) +7665172
System.Linq.Enumerable.ToList(IEnumerable`1 source) +61
FooRepository.List(Int32 count) in C:\...\FooRepository.cs:38
FooController.List() in C:\...\FooController.cs:30
lambda_method(ExecutionScope , ControllerBase , Object[] ) +39
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +17
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +178
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +24
System.Web.Mvc.<>c__DisplayClassa.<InvokeActionMethodWithFilters>b__7() +52
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +254
System.Web.Mvc.<>c__DisplayClassc.<InvokeActionMethodWithFilters>b__9() +19
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +192
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +399
System.Web.Mvc.Controller.ExecuteCore() +126
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +27
System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +7
System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext) +151
System.Web.Mvc.MvcHandler.ProcessRequest(HttpContext httpContext) +57
System.Web.Mvc.MvcHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext httpContext) +7
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +181
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75
InformationsquelleAutor Guillaume Gervais | 2010-01-05
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ein paar Vorschläge...
Erste, NHibernate standardmäßig lazy loading, also kann es auch gar nicht tun müssen, die mehr "effizient" Abfrage, die Sie versuchen.
Zweite, der folgende code tut nicht ganz das tun, was dein Beispiel-code enthält - es erstellt eine Liste von anonymen Typen namens miniFoos, enthalten eine Teilmenge der Felder in Foo. Aber der Effekt ist ähnlich zu dem, was Sie zu sein scheinen versuchen. Es nutzt auch was, wie ich glaube, namens LINQ-Methodensyntax.
Getestet habe ich diese auf eine Entität in meine eigene Anwendung, die auch über ein IList-Eigenschaft, und es funktioniert (obwohl ich sollte erwähnen, dass ich derzeit mit Eager loading). Ich habe gerade geschnitten und eingefügt, den funktionierenden code und ersetzt werden, z.B. deinen Namen.
OK, getestet habe ich den code und es scheint zu funktionieren, zumindest in den debugger. Weißt du, wie ich werfen kann, ist es zu einer konkreten IList<Foo - > (denn jetzt ist es nur eine Liste von anonymen Typ je nach compiler).
Ich bin Recht neu auf NH als gut, und haben hin und her gegangen auf Lazy Loading aus ähnlichen Gründen. Sie halten die session die ganze Zeit offen? Ich löste dies durch hinzufügen eines "session" - variable, die ich setzen, wenn ich starte mein Programm, und nur in der Nähe der session auf Programm beenden. Auf diese Weise, NH kümmert sich um alle schmutzige Arbeit für Sie, die eine der wichtigsten Gründe für den Einsatz von NH in den ersten Platz 😉
Ich glaube, dieses Beispiel ist mit LinqToObjects gegen die Query-API, nicht die NHibernate Linq-provider.
ja, bei der Reflexion, ich denke, du hast Recht. Nehme ich unten meine Antwort?
InformationsquelleAutor Tom Bushell
Ich versuchte die Beantwortung dieser bereits, bin aber nicht glücklich mit ihm.
Je mehr ich denke über Ihre Frage, desto mehr scheint es, wie Sie versuchen, Ihre eigene version von Lazy Loading, die NHibernate-Griffe ziemlich gut auf seine eigene, in meiner Erfahrung.
Weiß ich (aus einem Kommentar), dass Sie eingeschaltet, um Eager Loading, weil Sie waren nicht zu halten, eine Sitzung zu öffnen. Ich denke, es wäre mehr nützlich für Sie in der langen run wenn Sie fokussiert auf, dass der Winkel.
Wenn ich falsch verstanden habe, könnten Sie vielleicht Bearbeiten Sie die Frage, zu erklären, warum Sie denken, Sie müssen behandeln Sie es selbst?
Lazy loading funktioniert - glauben Sie mir! NH lädt nur die Daten für einen einzelnen member-variable in ein Objekt, wenn es ist, Lesen Sie direkt von Ihrem Programm. Das heißt, Sie können einfach laden Sie Foo und zeigen Sie das Bazes Sammlung an Ihre Benutzer. Bazes geladen wird, in der Bar nicht, da Sie nicht explizit in Ihrem code, obwohl Sie verweisen Foo. Vertrauen in die Kraft, Luke! Check out stackoverflow.com/questions/2013467/... für ein paar gute Ratschläge zu Sitzungen.
InformationsquelleAutor Tom Bushell
Konnte ich verwalten, um Projekte, die nicht die ganze Sammlung, sondern seine Felder
Kategoriename ist eine berechnete eingereicht im Forum Einheit
das nicht jede mapping mit DB -
Im Ergebnis bekam ich eine kleine Projektion des riesigen Forum Einheit und eine Möglichkeit zur Sortierung auf das Feld.
Hoffen, dass es hilft jemand.
InformationsquelleAutor imlarry
ich denke, Sie können Ihr problem lösen, indem Sie definieren das Ergebnis-Transformator und das Ergebnis-set-Namen, wenn in irgendeiner Weise Sie können auf die Kriterien, die generiert wird, können Sie vermeiden, anonymes Objekt.
das problem ist, dass die Eigentums-und Spaltennamen sind nicht die gleichen, und bei der Verwendung von Projektion nhibernate/linq to nhibernate nicht überprüfen, was den Namen der Spalte und den Namen der Eigenschaft. also, wenn u definiere Sie selbst in der Ergebnis-Eigenschaften (ich denke, die result set genannt) in den Kriterien, bevor Sie die Abfrage ausführen, sollte es funktionieren.
es ist ziemlich einfach, es zu versuchen,
InformationsquelleAutor Chen Kinnrot