我从这开始:
query
.Take(20)
.Select(item => new
{
id = item.SomeField,
value = item.AnotherField
})
.AsEnumerable()
.ToDictionary(item => item.id, item => item.value);
现在,我希望重用除SomeField
和AnotherField
之外的所有内容。
public static Dictionary<int, string> ReusableMethod<T>(
this IQueryable<T> query,
Func<T, int> key,
Func<T, string> value)
{
return query
.Take(20)
.Select(item => new
{
id = key(item),
value = value(item)
})
.AsEnumerable()
.ToDictionary(item => item.id, item => item.value);
}
query.ReusableMethod(item => item.SomeField, item => item.AnotherField);
这样可行,但数据库查询会选择多于所需的数据,因此我猜这意味着ReusableMethod
正在使用linq-to-objects。
是否可以在仅选择所需数据的情况下执行此操作?我将添加Func&lt;&gt;对我来说仍然是一个神奇的东西,所以我可能会遗漏一些明显的东西。
澄清以避免混淆:Take(20)
没问题,Select()
没有。
答案 0 :(得分:3)
使用Expression
包裹你的func并删除AsEnumerable
来电。
public static Dictionary<int, string> ReusableMethod<T>(
this IQueryable<T> query,
Expression<Func<T, int>> key,
Expression<Func<T, string>> value)
另一种方法是返回整行。在这种情况下无需Expression
。
return query
.Take(20)
.ToDictionary(key, value);
答案 1 :(得分:1)
最近我遇到了同样的问题,这就是我所做的:
您有一些DbEntity(由LINQ to EF,SQL生成),但您只想查询某些字段(我这样做是为了节省网络带宽)。您必须创建派生自DbEntity的类,因为您无法在Expression树中创建匿名类型,并且您无法在select语句中创建DbEntity的新实例。 (无需添加任何字段,属性等。)
公共类LocalEntity:DbEntity {}
您需要定义一个方法来生成选择表达式树。它看起来应该是这样的。这将生成类似于下面的表达式树:.Select(db =&gt; new LocalEntity(){Property1 = db.Property1,Proeprty2 = db.Property2})
protected Expression<Func<DbEntity, LocalEntity>> getSelectExpression()
{
ParameterExpression paramExpr = Expression.Parameter(typeof(DbEntity), "dbRecord");
var selectLambda = Expression.Lambda<Func<DbEntity, LocalEntity>>(
Expression.MemberInit(
Expression.New(typeof(LocalEntity)),
Expression.Bind(typeof(LocalEntity).GetProperty("DbEntityFieldName"), Expression.Property(paramExpr, "DbEntityFieldName"),
....
))
),
paramExpr);
return selectLambda;
}
像这样使用:
query.Select(getSelectExpression())ToDictionary();
将此更多地视为伪代码而不是C#代码,因为我必须对其进行大量简化并且无法对其进行测试,但是如果oyu使其工作,它将从您在getSelectedExpression中定义的仅DB字段传输,而不是整排。