My main objective is to create a dynamic group by and use it in NHibernate.
Consider this non dynamic example that works:
_repository.Collection<User>().GroupBy(u => new { u.Active }).Select(s => s.Key, Count = s.Count())
Now, I create a dynamic object to generate the new { u.Active }
part dynamically:
private Expression<Func<T, object>> CreateGrouping<T>(IEnumerable<string> by)
{
var dynamicTypeForGroup = GetDynamicTypeForGroup<T>(by);
var sourceItem = Expression.Parameter(typeof(T));
var bindings = dynamicTypeForGroup
.GetFields()
.Select(p => Expression.Bind(p, Expression.PropertyOrField(sourceItem, p.Name)))
.Cast<MemberBinding>()
.ToArray();
return Expression.Lambda<Func<T, object>>(Expression.Convert(
Expression.MemberInit(
Expression.New(dynamicTypeForGroup.GetConstructor(Type.EmptyTypes)),
bindings),
dynamicTypeForGroup),
sourceItem);
}
The type is generated in method GetDynamicTypeForGroup
and then instantiated with Expression.MemberInit(Expression.New(dynamicTypeForGroup.GetConstructor(Type.EmptyTypes)), bindings)
This is how the Type is generated:
private Type GetDynamicTypeForGroup<T>(IEnumerable<string> members)
{
var type = typeof(T);
var dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName(Guid.NewGuid().ToString()),
AssemblyBuilderAccess.RunAndSave
);
var dynamicModule = dynamicAssembly.DefineDynamicModule(Guid.NewGuid().ToString());
var typeBuilder = dynamicModule.DefineType(Guid.NewGuid().ToString());
var properties = members.Select(prop => type.GetProperty(ObjectExtensions.NormilizePropertyName(prop)))
.Where(prop => prop != null)
.Cast<MemberInfo>();
var fields = properties
.Select(property => typeBuilder.DefineField(
property.Name,
((PropertyInfo)property).PropertyType,
FieldAttributes.Public
)).Cast<FieldInfo>()
.ToArray();
GenerateEquals(typeBuilder, fields);
GenerateGetHashCode(typeBuilder, fields);
return typeBuilder.CreateType();
}
SO, THE PROBLEM
If I use _repository.Collection<User>().GroupBy(u => new { u.Active })
it works, but if I add the Select part - .Select(s => s.Key, Count = s.Count())
(or any select statment) I got the following NotSupportedException: MemberInit
System.NotSupportedException: MemberInit em NHibernate.Linq.Visitors.HqlGeneratorExpressionVisitor.VisitExpression(Expression expression) (ommited)
My doubt is:
- I know that NHibernate supports a Select statement with a group by and an anonymous type, but why it can't suport the Select if this type was created with the Expression Tree?
Aucun commentaire:
Enregistrer un commentaire