我想对仅在运行时已知的字段进行排序,并且该字段可以在select
子句内构建。
要求:
由于(3),直接实现不会从投影类中找到一个字段,因为我有一个静态类型的基类/实体类型。然后我开始改变代码来考虑结果类型。
我觉得这只是静态打字妨碍了,这在这里并没有真正帮助。遗憾的是IQueryable<dynamic>
不起作用。
示例代码(为简洁起见省略详细信息):
void Main()
{
using (var db = new MyContext())
{
var original = db.Set<Sample>();
// requirement (3), static type Sample, dynamic type SampleDTO
Expression<Func<Sample, Sample>> fn = item => new SampleDTO() { Description = "Value: " + item.Name};
var projected = original.Select(fn);
// requirements (1) and (2)
var ordered = OrderBy_Default<Sample, SampleDTO>(projected, "Description");
ordered.Dump();
}
}
private IQueryable<T> OrderBy_Default<T, TProject>(IQueryable<T> source, string ordering)
{
var type = source.ElementType;
var resultType = type;
var property = resultType.GetProperty(ordering, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
var parameter = Expression.Parameter(resultType, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExp = Expression.Lambda(propertyAccess, parameter);
MethodCallExpression resultExp = Expression.Call(typeof(Queryable),
"OrderBy",
new Type[] { type, property.PropertyType },
source.Expression, Expression.Quote(orderByExp));
return source.Provider.CreateQuery<T>(resultExp);
}
前面的代码产生了这个错误:
类型'Queryable'上没有泛型方法'OrderBy'与提供的类型参数和参数兼容。如果方法是非泛型的,则不应提供类型参数。
我试过projected.Cast<SampleDTO>()
:
无法将“Sample”类型转换为“UserQuery + SampleDTO”类型。 LINQ to Entities仅支持转换EDM原语或枚举类型。
我试过projected.OfType<SampleDTO>()
:
'UserQuery + SampleDTO'不是类型过滤操作的有效元数据类型。类型过滤仅对实体类型和复杂类型有效。
Cast()
和OfType()
适用于L2O,但不适用于L2EF。
将SampleDTO
添加到实体模型当然不是答案(尽管已经尝试过,但为了解它是如何工作的。)
我的实体&amp;突起:
public class Sample
{
public int Id { get; set; }
public string Name { get; set; }
}
public class SampleDTO: Sample
{
public string Description { get; set; }
}
我让SampleDTO继承自Sample,它有点帮助。这不是一个要求,这是一个方便的问题。
一些可能的答案:
而不是Expression<Func<Sample, Sample>>
我可以拥有Expression<Func<Sample, SampleDTO>>
。这使得require(3)无效,并且会破坏我现有的大部分代码。
答案 0 :(得分:0)
这对我有用,如果我正确理解你的问题,但我感觉我错过了什么
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering)
{
var type = typeof(T);
var property = type.GetProperty(ordering);
var parameter = Expression.Parameter(type);
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExp = Expression.Lambda(propertyAccess, parameter);
MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderBy", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));
return source.Provider.CreateQuery<T>(resultExp);
}