创建动态group by子句 [英] Create a dynamic group by clause

查看:93
本文介绍了创建动态group by子句的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下小组:





Hi peeps I have the following group by :


var groupedData = outputTable.AsEnumerable()
    .GroupBy(x => new { name = x.Field<string>("name"), source = x.Field<string>     ("source"), destination = x.Field<string>("destination") }).ToList();





这是有效的,但源和目标可以是我从数据库中提取的任何内容,因为我需要使这些分组动态化。所以我想构建一种这样的组字符串:





this works but source and destination could be anything that I pull from the database as I need to make these groupings dynamic. So I want to build a kind of group string like this :

string dyno = "name = x.Field(\"name\"), sourceAddress = x.Field(\"sourceAddress\"), destinationAddress = x.Field(\"destinationAddress\")";





然后说:



and then say:

var groupedData = outputTable.AsEnumerable()
    .GroupBy(x => new { dyno }).ToList();





这可能吗?



我尝试了什么:





is this possible?

What I have tried:

string bob = "name = x.Field<string>(\"name\"), sourceAddress = x.Field<string>(\"sourceAddress\"), destinationAddress = x.Field<string>(\"destinationAddress\")";

var groupedData = outputTable.AsEnumerable().GroupBy(x => new { x =>  bob }).ToList();

推荐答案

这可能是一个非常高级的主题:您必须使用表达式(名称空间System.Linq.Expression)手动构建group-by子句:表达式树(C#和Visual Basic) [ ^ ]



我已经为动态where-clause和join-clause做了这个,但是还没有用group-by-clause,所以我没有准备好示例代码。您可以通过以下Google搜索结果找到有用的信息: linq dynamic group by - Google搜索 [ ^ ]



另一种方法是通过迭代进行没有LINQ的分组您的DataTable行和构建组(某些集合对象)的行在相关列中具有相同的值。



编辑:

只记得那里有一个LINQ动态查询库,允许做一些动态LINQing。不确定它是否能够做你想要的但是你可以尝试一下。我假设您必须将DataTable转换为类对象的集合。

ScottGu的博客 - 动态LINQ(第1部分:使用LINQ动态查询库) [ ^ ]
It's possible but a really advanced topic: You would have to build the group-by clause "manually" with expressions (namespace "System.Linq.Expression"): Expression Trees (C# and Visual Basic)[^]

I've done that for dynamic where-clauses and join-clauses but not with a group-by-clause yet, so I don't have a sample code ready. You might find something helpful with these Google search results: linq dynamic group by - Google Search[^]

The alternative would be to do the grouping without LINQ, by iterating over the rows of your DataTable and building groups (some collection object) of rows that have the same values in the relevant columns.


Just remembered that there's a "LINQ Dynamic Query Library" out there which allows to do some "dynamic LINQing". Not sure if it will be able to do what you want but you might give it a try. I assume you would have to transform your DataTable into a collection of class-objects though.
ScottGu's Blog - Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)[^]


动态LINQ [ ^ ]是一个选项,但它有一些缺点。您必须使用类似于松散基于VB.NET的语法将列名列表格式化为适当的查询;并且,由于无法在运行时创建匿名类型,因此库必须为每组使用的列发出并加载新的内存中程序集。



根据您对组的操作,您可能更幸运使用自定义类来定义分组:

Dynamic LINQ[^] is one option, but it has some drawbacks. You have to format the list of column names into an appropriate query, using a syntax that looks like it's loosely based on VB.NET; and, as there's no way to create an anonymous type at runtime, the library has to emit and load a new in-memory assembly for each set of columns used.

Depending on what you're doing with the groups, you might have better luck using a custom class to define the grouping:
public sealed class DynamicDataRowGroup : DynamicObject, ICustomTypeDescriptor, IEquatable<DynamicDataRowGroup>
{
    private readonly DataRow _row;
    private readonly ISet<string> _columns;
    private readonly PropertyDescriptorCollection _properties;
    
    public DynamicDataRowGroup(DataRow row, IEnumerable<string> columns)
    {
        if (row == null) throw new ArgumentNullException("row");
        if (columns == null) throw new ArgumentNullException("columns");
        
        _row = row;
        _columns = new HashSet<string>(columns, StringComparer.OrdinalIgnoreCase);
        
        var properties = _columns.Select(name => DynamicDataRowGroupProperty.Create(row, name));
        _properties = new PropertyDescriptorCollection(properties.ToArray<PropertyDescriptor>(), true);
    }
    
    public DynamicDataRowGroup(DataRow row, params string[] columns) : this(row, columns.AsEnumerable())
    {
    }
    
    public override int GetHashCode()
    {
        int result = 0;
        foreach (string column in _columns)
        {
            object value = _row[column];
            int code = (value == null) ? 0 : value.GetHashCode();
            result = unchecked((result * 397) + code);
        }
        
        return result;
    }
    
    public override bool Equals(object obj)
    {
        return Equals(obj as DynamicDataRowGroup);
    }
    
    public bool Equals(DynamicDataRowGroup other)
    {
        if (ReferenceEquals(other, null)) return false;
        if (ReferenceEquals(other, this)) return true;
        if (!_columns.SetEquals(other._columns)) return false;
        return _columns.All(c => Equals(_row[c], other._row[c]));
    }
    
    public override IEnumerable<string> GetDynamicMemberNames()
    {
        return _columns;
    }
    
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (_columns.Contains(binder.Name))
        {
            result = _row[binder.Name];
            return true;
        }
        
        return base.TryGetMember(binder, out result);
    }
    
    public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
    {
        if (indexes != null && indexes.Length == 1)
        {
            string name = indexes[0] as string;
            if (name != null && _columns.Contains(name))
            {
                result = _row[name];
                return true;
            }
        }
        
        return base.TryGetIndex(binder, indexes, out result);
    }

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
    {
        return _properties;
    }

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
    {
        return _properties;
    }
    
    object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
    {
        return this;
    }

    PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
    {
        return null;
    }
    
    AttributeCollection ICustomTypeDescriptor.GetAttributes()
    {
        return AttributeCollection.Empty;
    }

    EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
    {
        return EventDescriptorCollection.Empty;
    }
    
    EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
    {
        return EventDescriptorCollection.Empty;
    }

    EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
    {
        return null;
    }

    string ICustomTypeDescriptor.GetClassName()
    {
        return null;
    }

    string ICustomTypeDescriptor.GetComponentName()
    {
        return null;
    }

    TypeConverter ICustomTypeDescriptor.GetConverter()
    {
        return null;
    }

    object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
    {
        return null;
    }
    
    private sealed class DynamicDataRowGroupProperty : PropertyDescriptor
    {
        private static readonly Attribute[] EmptyAttributes = new Attribute[0];
        private readonly Type _propertyType;
        
        private DynamicDataRowGroupProperty(string name, Type propertyType) : base(name, EmptyAttributes)
        {
            _propertyType = propertyType;
        }

        public override Type ComponentType
        {
            get { return typeof(DynamicDataRowGroup); }
        }

        public override Type PropertyType
        {
            get { return _propertyType; }
        }

        public override bool IsReadOnly
        {
            get { return true; }
        }

        public override object GetValue(object component)
        {
            var group = component as DynamicDataRowGroup;
            return (group == null) ? null : group._row[Name];
        }

        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }

        public override bool CanResetValue(object component)
        {
            return false;
        }

        public override void ResetValue(object component)
        {
            throw new NotSupportedException();
        }

        public override void SetValue(object component, object value)
        {
            throw new NotSupportedException();
        }
        
        public static DynamicDataRowGroupProperty Create(DataRow row, string name)
        {
            DataColumn column = row.Table.Columns[name];
            if (column == null) throw new ArgumentException(string.Format("Column '{0}' was not found.", name));
            return new DynamicDataRowGroupProperty(name, column.DataType);
        }
    }
}



有了这个类,你现在可以像这样对行进行分组:


With that class in place, you can now group your rows like this:

var groupedData = outputTable.AsEnumerable()
    .GroupBy(row => new DynamicDataRowGroup(row, "name", "sourceAddress", "destinationAddress"))
    .ToList();



你可以将密钥转换为 dynamic 并直接访问属性:


You can either cast the keys to dynamic and access the properties directly:

dynamic key = groupedData[0].Key;
string name = key.name;



或者您可以使用任何依赖的绑定机制 TypeDescriptor (例如ASP.NET中的 Eval )来检索属性:


Or you can use any binding mechanism that relies on the TypeDescriptor (such as Eval in ASP.NET) to retrieve the properties:

<asp:literal runat="server"

    Text='<%# Eval("Key.name") %>'

/>


这篇关于创建动态group by子句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆