C# Linq 行到列

C# Linq rows to column

我想将 linq 结果从行变成列,字段名称是用户可以更改的,所以我需要函数是动态的。

示例数据

ID: 331   FieldName: "BusinessCategory"  FieldContents: "Regulatory" 
ID: 331   FieldName: "PriorityGroup"     FieldContents: "Must Do" 
ID: 332   FieldName: "BusinessCategory"  FieldContents: "Financial" 
ID: 332   FieldName: "PriorityGroup"     FieldContents: "Should Do" 

转成(样本结束输出)

ID   BusinessCategory    PriorityGroup
331  Regulatory          Must Do
332  Financial           Should DO

这是从数据库中提取字段名和内容的代码块。

public static IEnumerable<InitProjectValues1> GetProgramInitiativeAttributesPart1(int id)
{
    using (dpm db = new dpm())
    {
        string partit = (string)HttpContext.Current.Session["sitePart"];

        var configrefs = from c in (
                from e in db.Metrics
                join j in db.ProgramLink on e.ProjectRef equals j.LinkedProject
                where (j.ProjectRef == id) && e.PartitNo == partit                    
                select new
                {
                    FieldName = e.FieldName,
                    FieldContents = e.MetricValue,
                    ProjectRef = e.ProjectRef,

                })
                         select new InitProjectValues1
                         {
                             ProjectRef = c.ProjectRef,
                             FieldName = c.FieldName,                                 
                             FieldContents = c.FieldContents,
                         };         //somewhere here would be the code to cover this into a single row per ProjectRef number.

        return configrefs.ToList();
    }

}

这是数据模型。

public class InitProjectValues1
{
    public int? ProjectRef { get; set; }
    public string FieldName { get; set; }
    public string FieldContents { get; set; }
}

我真的不知道该何去何从,希望有人能提供指导/示例代码

您需要的这种操作称为枢轴。您实际上是在围绕唯一的 productRef 旋转 table 并将行更改为列。

您可以尝试使用动态对象来生成动态列。

var configrefs = from c in (
            from e in db.Metrics
            join j in db.ProgramLink on e.ProjectRef equals j.LinkedProject
            where (j.ProjectRef == id) && e.PartitNo == partit                    
            select new
            {
                FieldName = e.FieldName,
                FieldContents = e.MetricValue,
                ProjectRef = e.ProjectRef,

            }).ToArray();

return configrefs.ToPivotArray(
                                i => i.FieldName, 
                                i => i.ProjectRef,
                                items => items.Any() ? items.FirstOrDefault().FieldContents : null);

获取动态对象的私有方法:

private static dynamic GetAnonymousObject(IEnumerable<string> columns, IEnumerable<object> values)
{
   IDictionary<string, object> eo = new ExpandoObject() as IDictionary<string, object>;
   int i;
   for (i = 0; i < columns.Count(); i++)
   {
       eo.Add(columns.ElementAt<string>(i), values.ElementAt<object>(i));
   }
   return eo;
}

以及扩展方法

public static dynamic[] ToPivotArray<T, TColumn, TRow, TData>(
    this IEnumerable<T> source,
    Func<T, TColumn> columnSelector,
    Expression<Func<T, TRow>> rowSelector,
    Func<IEnumerable<T>, TData> dataSelector)
{

       var arr = new List<object>();
       var cols = new List<string>();
       String rowName = ((MemberExpression)rowSelector.Body).Member.Name;
       var columns = source.Select(columnSelector).Distinct();       

       cols =(new []{ rowName}).Concat(columns.Select(x=>x.ToString())).ToList();


       var rows = source.GroupBy(rowSelector.Compile())
                        .Select(rowGroup => new
                        {
                            Key = rowGroup.Key,
                            Values = columns.GroupJoin(
                                rowGroup,
                                c => c,
                                r => columnSelector(r),
                                (c, columnGroup) => dataSelector(columnGroup))
                        }).ToArray();


       foreach (var row in rows)
       {
           var items = row.Values.Cast<object>().ToList();
           items.Insert(0, row.Key);
           var obj = GetAnonymousObject(cols, items);
           arr.Add(obj);               
       }
       return arr.ToArray();
}