首页 > 解决方案 > 如何让用户指定在运行时在 Linq-to-Objects GroupBy 查询表达式中使用哪些实体属性?

问题描述

背景故事:

所以我有一个我正在研究的小演示应用程序,它正在查看歌曲并尝试根据用户指定的标签查找重复项。最初,我只是使用我试图概括的以下查询。

var query = MusicFiles.GroupBy(x => 
        new { x?.Tag.FirstArtist, x?.Tag.Title }
    ).Where(g => g.Count() > 1)
    .ToList();

现在虽然我想让用户指定这些属性,所以我使用反射来获取TagLib.Tag类的所有属性,现在允许用户指定他们感兴趣的标签。

问题:

我如何使用这个新的字符串列表来表示所有这些属性的类和组的属性,或者如何概括上面的代码行。

我最初的思路和我尝试过的一直是尝试创建一个像上面这样的匿名对象并使用反射来获取每个属性,但是由于我正在遍历字符串属性列表,所以我最终得到了一个匿名对象每个属性而不是所有选定属性的匿名对象

标签: c#linq

解决方案


我刚刚为数据透视表样式报告构建了类似的东西,我现在无法与您分享。我的建议是从包含所有可能的分组字段的表达式开始模板分组。然后创建一个ExpressionVisitor以查找MemberInitExpression,并删除MemberBinding用户尚未选择的任何内容。这样,您仍然拥有一个强类型的表达式组,它可以使用 EF Core 的任何功能,而无需重新实现它。

Expression<Func<X,TagGroup>> template = x => 
        new TagGroup { x?.Tag.FirstArtist, x?.Tag.Title, ... };

public Filter : ExpressionVisitor{
    public Filter(... selection){ ... }
    protected override Expression VisitMemberInit(MemberInitExpression node){
        return node.Update(node.NewExpression, node.Bindings.Where( ... ));
    }
}

var groupBy = new Filter(selection).Visit(template);

填空作为练习。


推荐阅读