verwendetes Datenbanksystem: SQL Server 2008 R2 // NHibernate
Hallo Community,
ich komme bei einem Problem einfach nicht weiter. Ich stelle für die Entitäten meiner Anwendung jeweils ein Repository zur Verfügung. In diesem Repository möchte ich eine Methode zur Verfügung stellen, die alle Entitäten ausließt und der ich als Parameter übergeben kann welche Childnodes mitgeladen werden sollen.
Hierzu habe ich mir folgende Methode überlegt:
public IEnumerable<User> FindAll<TRelated>(Expression<Func<User, IEnumerable<TRelated>>> fetchExpression) {
return session.Query<User>().Fetch(fetchExpression);
}
Soweit, so gut. Nun bin ich aber nicht in der Lage diese Methode aufzurufen. Ich würde gerne wie folgt die Methode aufrufen:
var user = repository.FindAll(x => new[] { x.Orders, x.Roles });
Das geht aber leider nicht, da Orders
und Roles
nicht vom gleichen Typ sind. Hat jemand eine Idee oder sieht meinen Denkfehler?
Wer nicht wagt .. der nicht gewinnt .. !
Hallo mctimotheus,
wenn ich das richtig verstanden habe, dann willst du bestimmte Childs je nach bedarf Eager laden oder? Ich würde für jeden Bedarf eine einzelne Methode zur verfügung stellen.
Z.B.:
public IEnumerable<User> FindAllWithOrdersAndRoles() {}
public IEnumerable<User> FindAllWithOrders() {}
public IEnumerable<User> FindAllWithRoles() {}
Btw. das ist nicht wirklich eine NHibernate bezogene Frage, da die Session die du nutzt auch keine ISession zu sein scheint. Zumindest hat die ISession in NHibernate keine "Query()" funktion.
MfG
Rabban
Wenn du den Namespace NHibernate.Linq
einbindest hast du auch die Query()
Methode in deiner Session zur Verfügung. Dann kannst du wie in Entity Framework auch übliche LINQ-Abfragen absetzen.
Die Variante für jeden Fall des Nachladens eine eigene Methode zu schreiben halte ich für etwas ungeeignet, da man ja auch das Nachladen der Childs kombinieren können soll. Also Beispielsweise so: Lade mir alle User mit den dazugehörigen Rollen und Aufträgen aber nicht das IT-Equiment der User.
Wer nicht wagt .. der nicht gewinnt .. !
Hallo mctimotheus,
also Typensicher geht es nur wie Rabban es vorgeschlagen hat (so weit ich sehe).
Wenn man aber auf die Typensicherheit verzichtet, kann man mit Reflection hier etwas machen.
Dazu muss man die Properties übergeben und nicht deren inhalt (so wie in deinem Code).
Gruß
Juy Juka
IUser x = null;
IEnumerable<IUser> userList = null;
userList = repository.FindAll(()=>x.Orders, ()=>x.Roles);
userList = repository.FindAll();
userList = repository.FindAll(()=>x.Roles);
...
using System;
using System.Linq.Expressions;
using System.Reflection;
...
public virtual void IEnumerable<IUser> FindAll(params Expression<Func<object>>[] properties)
{
...
foreach(Expression<Func<object>> zwi in properties)
{
PropertyInfo property = Helper.PropertyOf(zwi);
// jetzt wie auch immer das Property "eager fetch" markieren/machen/laden/...
...
}
...
}
...
internal static class Helper
{
public static PropertyInfo PropertyOf(Expression<Func<object>> property)
{
PropertyInfo propertyInfo = null;
MemberExpression memberExpression = property == null ? null : property.Body as MemberExpression;
UnaryExpression unaryExpression = property == null ? null : property.Body as UnaryExpression;
if (memberExpression != null)
{
propertyInfo = memberExpression.Member as PropertyInfo;
}
else if (unaryExpression != null)
{
propertyInfo = ((MemberExpression)(unaryExpression).Operand).Member as PropertyInfo;
}
if (propertyInfo == null)
{
throw new ArgumentException(Properties.Resources.LambdaFehler);
}
return propertyInfo;
}
}
}
Sehr interessanter Ansatz JuyJuka, ich werds mal bei gelegenheit ausprobieren.
Btw. Die Url aus deiner Signatur geht nicht^^
MfG
Rabban