2

我从这个开始:

query
    .Take(20)
    .Select(item => new
    {
        id = item.SomeField,
        value = item.AnotherField
    })
    .AsEnumerable()
    .ToDictionary(item => item.id, item => item.value);

现在,我想重用除SomeFieldand之外的所有内容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<> 对我来说仍然是魔法的一部分,所以我可能会遗漏一些明显的东西。

澄清以避免混淆:Take(20)很好,Select()不是。

4

2 回答 2

3

Expression用并删除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);
于 2012-11-27T14:37:21.020 回答
1

最近我遇到了同样的问题,这就是我所做的:

  1. 您有一些 DbEntity(由 LINQ to EF、SQL 生成),但您只想查询一些字段(我这样做是为了节省网络带宽)。您必须创建从 DbEntity 派生的类,因为您不能在表达式树中创建匿名类型,并且您不能在 select 语句中创建 DbEntity 的新实例。(无需添加任何字段、属性等)

    公共类 LocalEntity : DbEntity {}

  2. 您需要定义一个方法来生成您的选择表达式树。它应该看起来像这样。这将生成类似于以下的表达式树: .Select(db => 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;
    }
    
  3. 像这样使用它:

    query.Select(getSelectExpression()).ToDictionary();

将其视为伪代码而不是 C# 代码,因为我必须对其进行大量简化并且无法对其进行测试,但是如果 oyu 使其工作,它将仅从您在 getSelectedExpression 中定义的 DB 字段传输,而不是整行.

于 2012-11-27T15:56:45.977 回答