传递Func<>选择

时间:2012-11-27 14:35:27

标签: c# linq linq-to-sql

我从这开始:

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

现在,我希望重用除SomeFieldAnotherField之外的所有内容。

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()没有。

2 个答案:

答案 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)

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

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

    公共类LocalEntity:DbEntity {}

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

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

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

相关问题