【问题标题】:c# List<string> to Lambda Expression with starter example: Refactor to handle the Listc# List<string> to Lambda Expression with starter example: Refactor to handle the List
【发布时间】:2010-11-02 21:45:36
【问题描述】:

我有这个:

List<string> fields;

fields[0] = "firstFieldName";
fields[1] = "secondFieldName";
...
fields[n] = "nthFieldName";

我想得到这个:

var selector = p => new {p.firstField, p.secondField, ..., p.nthFieldName}

// selector is of type Expression<Func<Entity, object>>

GoofBallLogic 有类似的this code,最后是p =&gt; p.column

// Entity is an object in a diagram from Entity Framework 4
var p = Expression.Parameter(typeof(Entity, "p");

var selector = Expression.Lambda<Func<Entity, string>(
    Expression.Property(p, columnToGroupBy), p );

编辑:我想要完成的事情

我有一个“通用”存储库:

public class Repository<E, C> : IRepository<E,C>
{
    private C _dc {get;set;} // ObjectContext (Entity Framework 4)
    private string _entityName {get;set;}
    public string entityKeyName {get;private set;}
    public List<string> entityKeys {get;private set;}
    public Expression<Func<E, object>> entityKey {get;private set;}
    private EntityContainer _containerName {get;set;}

    public Repository(C myDC)
    {   _dc = myDC; // TODO: check for null

        // Name of "this" ObjectContext
        _containerName = _dc.MetadataWorkspace.GetEntityContainer(
            _dc.DefaultContainerName, DataSpace.CSpace);

        // Name of "this" Entity
        _entityName = _containerName.BaseEntitySets
            .Where(p => p.ElementType.Name == typeof (E).Name)
            .Select( p => p.Name).FirstOrDefault();

        // String list of the keys
        entityKeys = _containerName
            .BaseEntitySets.First(meta => meta.ElementType.Name == 
                typeof(E).Name)
            .ElementType.KeyMembers.Select(k => k.Name).ToList();

        // Thanks Jon Skeet for this cool comma sep list formula
        entityKeyName = string.Join(",", entityKeys.ToArray() );  

        entityKey = Expression.Lambda<Func<E, object>> ... 

如何将 entityKey 设置为可用于 一个 OrderBy 语句,因为 Linq to Entities 需要 在执行 .Skip().Take() 之前订购一套

编辑:

令人惊讶的是,Orderby 可以接受这个:

p => "field1,field2,field3"

这允许我的代码执行,但实际上并没有按字段值对项目进行排序。我猜这是 TDD 的第一步:使用文字。

【问题讨论】:

  • 您能更具体地说明您要完成的工作吗?比如,你想在哪个上下文中使用选择器?
  • “匿名”类型实际上是实体的键。我们不必对此匿名。 :)
  • using p => "field1,field2,field3" 不会进行任何排序,因为您按字符串 "field1,field2,field3" 对每个值进行排序,因此它们都是相同的。
  • 您在某些字段上使用了下划线,而在其他字段上没有。您正在赞扬 Jon Skeet 的一个非常基本的基本函数调用。我的印象是,您通过粘贴来自不同人的代码将其拼接在一起,并且没有费心做任何自己的想法......
  • 下划线是私有变量。我在使用时会记下其他代码。当我花太长时间自己解决问题时,我会在 SO 上提出问题。在 Timwi 要求澄清问题之前,我没有发布该代码。

标签: c# entity-framework-4 lambda


【解决方案1】:

我发现这是一个有趣的问题并花了一些时间来解决它,并找到了一种相对简单的方法。

无论如何,这是一个关于如何进行单个字段排序的示例(我将使用您的第一个字段),如果您想对更多字段进行排序,您也必须为它们创建表达式并使用 .ThenBy(xxx ) 在通常的 OrderBy(xxx) 之后。

    // Create a parameter which passes the object
    ParameterExpression param = Expression.Parameter(typeof(E), "a");

    // Create body of lambda expression
    Expression body = Expression.PropertyOrField(param, fieldname);

    // Create lambda function
    Expression<Func<E, string>> exp = Expression.Lambda<Func<E, string>>(body, param);

    // Compile it so we can use it
    Func<E, string> orderFunc = exp.Compile();

现在您可以执行 OrderBy(orderFunc),它会根据 fieldname 中命名的属性对列表进行排序。唯一的缺点是它仅适用于字符串字段(表达式的返回值)。不过可能也可以解决这个问题。

已修复以适用于任何 IComparable 类型:

        // Create a parameter which passes the field
        ParameterExpression param = Expression.Parameter(typeof(E), "a");

        // Create body of lambda expression
        Expression body = Expression.TypeAs(Expression.PropertyOrField(param, fieldname), typeof(IComparable));

        // Create lambda function
        Expression<Func<E, IComparable>> exp = Expression.Lambda<Func<E, IComparable>>(body, param);

        // Compile it so we can use it
        Func<E, IComparable> orderFunc = exp.Compile();

【讨论】:

  • 很好,因为我收到了一个逗号分隔的 OrderBy 字段列表,按需要的顺序排列。我现在就试试。 :)
【解决方案2】:

您不能轻易做到这一点,因为您无法为运行时不存在的类型构造 new 表达式。 (您可以在 C# 中使用匿名类型,因为 C# 编译器会为您创建类型。)

如果您想以 非常困难的方式 做到这一点,您可以生成一个动态程序集并实际创建您需要的类型。有一个short example here

不过,我怀疑有一种更简单的方法。我们需要知道您没有说明的目标是什么(您需要这个表达式树来做什么)。

【讨论】:

  • 我将很快添加代码来演示我正在尝试做的事情。 :)
【解决方案3】:

从您编辑的问题来看,您似乎只是希望能够通过多个键进行排序。这很容易通过使用.OrderBy() 后跟.ThenBy() 来实现。我假设你在这里使用IQueryable&lt;E&gt;

IQueryable<E> query = ...;
IOrderedQueryable<E> ordered = null;

foreach (var key in entityKeys)
{
    // Code from Doggett to construct the lambda expression for one step
    ParameterExpression param = Expression.Parameter(typeof(E), "a");
    var body = Expression.TypeAs(
        Expression.PropertyOrField(param, key),
        typeof(IComparable));
    var exp = Expression.Lambda<Func<E, IComparable>>(body, param);

    if (ordered == null)
        ordered = query.OrderBy(exp);
    else
        ordered = ordered.ThenBy(exp);
}

var finalQuery = (ordered ?? query).Skip(n).Take(m);

【讨论】:

    猜你喜欢
    • 2022-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-27
    • 2021-08-05
    • 2021-07-13
    • 1970-01-01
    相关资源
    最近更新 更多