【问题标题】:How can I combine two LINQ select expressions?如何组合两个 LINQ 选择表达式?
【发布时间】:2020-07-15 09:49:26
【问题描述】:

我正在尝试使用可以根据我从输入中收到的内容逐步更新的选择表达式,如下所示:

// Init expression
Expression<Func<Order, object>> selectExpression = x => new
{
    x.Id
};

if(selectInput.Title){
    // something like this
    selectExpression = selectExpression.Add(x => new
    {
        x.Title
    });
}
if(selectInput.ClientFullName){
    // something like this
    selectExpression = selectExpression.Add(x => new
    {
        ClientFullname = x.Client.Fullname
    });
}

// Use expression in a LINQ query (for an EF Core query)
var result = await queryable.Select(selectExpression).ToListAsync();

那么我希望得到这样的结果

{
    "Id": 568,
    "Title": "Order 567",
    "ClientFullname": "John Smith"
}

这是可能的吗?我在网上找到的唯一例子是关于 .Where()。我是不是走错方向了?

谢谢!

【问题讨论】:

  • 这比看起来要难得多。这些匿名类型是由编译器在编译时生成的:您不能只是在运行时将ClientFullname 字段动态添加到类型上。使用字典会更容易(但仍然有点繁琐)
  • 你只有一个字典
  • LINQ 的重点是在编译时知道查询的结构。如果不是这种情况,最好使用较旧的工具来查询数据库,这些工具本质上不会静态定义查询结果的模式。您为自己创造的工作比使用 LINQ 节省的工作要多。

标签: c# linq linq-to-sql entity-framework-core


【解决方案1】:

如果您这样做,那么问题是,您的编译器将不知道属性 ClientFullName 是否是结果中的属性,因此您的编译器无法使用它。

当然,您可以使用属性名称作为标识符,并将所有内容放入字典中。就像@Canton7 建议的那样。

如果您不期望 null 值,您可以返回一个包含所有属性的类。值为 null 的属性将不会被选中:

class MyItem
{
    public int Id {get; set;}              // Id always fetched
    public string Title {get; set;}
    public DateTime? Date {get; set;}
    ... // etc: all nullable properties
}

作为扩展方法:

public static IQueryable<MyItem> ToSelectedItems(
    this IQueryable<Order> orders,
    SelectedInput selectedInput)
{
    // TODO: exception if orders or selectedInput null

    return orders.Select(order => new MyItem
    {
        Id = order.Id,

        // properties null if not in selectedInput
        Title = selectedInput.Title ? order.Title : null,
        ClientFullName = selectedInput.ClientFullName ? order.ClientFullName : null,
        Date = selectedInput.Date ? order.Date : null,
     })

【讨论】:

  • 哇,这是一个非常聪明的方法!我会尝试并在这里报告结果。谢谢!
【解决方案2】:

您可能会发现 LinqKit 很有用: (http://www.albahari.com/nutshell/linqkit.aspx) 在尝试针对 IQueryable 数据源编写变量 where 子句时,我已经多次使用它。 PredicateBuilder (http://www.albahari.com/nutshell/predicatebuilder.aspx) 对于构建动态查询表达式非常有用。

示例代码是这样的......

    public void QueryItems(string id, string name, string fullname)
    {
        // this would be the collection od data to be filtered
        var items = new List<Item>();

        // initialise predicate of for querying objects of type Item
        var predicate = PredicateBuilder.New<Item>();

        // dynamically add clauses dependent on available filter values
        if (!string.IsNullOrEmpty(id))
        {
            predicate = predicate.And(x => x.Id == id);
        }
        if (!string.IsNullOrEmpty(name))
        {
            predicate = predicate.And(x => x.Name == name);
        }
        if(!string.IsNullOrEmpty(fullname))
        {
            predicate = predicate.And(x => x.FullName == fullname);
        }

        // evaluate the result of the dynamic query
        var result = items.Where(predicate).ToList();
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多