从linq2entities返回一个多维关联对象

时间:2016-09-04 08:02:05

标签: c# entity-framework linq linq-to-entities

免责声明:非常第一个c#项目

我正在处理一个导出脚本,需要将数据从sql数据库导出到csv。我试图让linq2entities完成大部分繁重的工作,这样我就可以避免不必要的循环。

我想将linq2sql响应分成2个对象(或子对象在下面称为“calcs”),其子内容需要能够为我提供一个键/值对,因为我需要稍后在我的计算中的键名称将输出分配给另一个表中的映射键。

我尝试了几次迭代,但不能用于以下工作。语法看起来是正确的但是现在(下面)我甚至无法获得计数(Any),如果我只是将它指定为普通列表我得到一个rowcount但是我无法访问第二个foreach循环中的子对象

所以可以从linq2sql返回一个混合的“子对象”,如果没有,我的选择是什么?

  public ActionResult Process()
    {
        // Getting the data:
        using (printmanEntities db = new printmanEntities())
        {

            var result = (
                from u in db.CustomerUsages
                join c in db.Customers on u.CustomerId equals c.Id
                join e in db.Centers on u.CenterId equals e.id
                where u.Status == 1
                group u by c.Code into gr
                select new
                {
                    CustomerId = gr.Key,
                    CenterCode = gr.FirstOrDefault().Center.CenterCode,
                    CustomerCode = gr.FirstOrDefault().Customer.Code,
                    // Is the below possible?
                    calcs = new List<KeyValuePair<string, int>>
                    {
                         new KeyValuePair<string,int>("TPrintBw",gr.Sum(u => u.TPrintBw)) ,
                         new KeyValuePair<string, int>("TPrintCol", gr.Sum(u => u.TPrintCol)),
                         new KeyValuePair<string, int>("TCopyBw", gr.Sum(u => u.TCopyBw)),
                         new KeyValuePair<string, int>("TCopyCol", gr.Sum(u => u.TCopyCol)),
                         new KeyValuePair<string, int>("TScan", gr.Sum(u => u.TScan)),
                         new KeyValuePair<string, int>("TFaxBw", gr.Sum(u => u.TFaxBw))
                    }
                });

            if (result.Any())
            {

                AllCodes = db.Codes.ToList();

                dt.Columns.Add("Date", typeof(DateTime));
                dt.Columns.Add("CenterCode", typeof(String));
                dt.Columns.Add("BLANK", typeof(String));
                dt.Columns.Add("CustomerCode", typeof(string));
                dt.Columns.Add("ServiceCode", typeof(string));
                dt.Columns.Add("Qty", typeof(Int32));

                foreach (var v in result)
                {
                    // I need to iterate through the items in the subobject here:
                    foreach (var i in v.calcs)
                    {
                        if (i.Value > 0)
                        {
                            DataRow dr = dt.NewRow();
                            dr["Date"] = DateTime.Now;
                            dr["CenterCode"] = v.CenterCode;
                            dr["BLANK"] = "";
                            dr["CustomerCode"] = v.CustomerCode;
                            dr["ServiceCode"] = GetServiceCode(i.Key);
                            dr["Qty"] = i.Value;
                            dt.Rows.Add(dr);
                        }

                    }
                }

                StringBuilder sb = new StringBuilder();

                IEnumerable<string> columnNames = dt.Columns.Cast<DataColumn>().
                                                  Select(column => column.ColumnName);
                sb.AppendLine(string.Join(",", columnNames));

                foreach (DataRow row in dt.Rows)
                {
                    IEnumerable<string> fields = row.ItemArray.Select(field => field.ToString());
                    sb.AppendLine(string.Join(",", fields));
                }
                string filename = DateTime.Now.ToString("yyyyddMM") + ".csv";
                System.IO.File.WriteAllText(HttpContext.Server.MapPath(@"/csv/exports/" + filename), sb.ToString());

            }
        }

        return View();
    }

1 个答案:

答案 0 :(得分:0)

您的查询的问题是LINQ to Entities需要使用无参数构造函数和属性设置器投影到类型,而KeyValuePair(以及Tuple)不符合该条件且无法使用。

一种方法是创建和投影到您自己的类型,类似于KeyValuePair但与EF兼容:

public class KeyValuePairDto<TKey, TValue>
{
    public TKey Key { get; set; }
    public TValue Value { get; set; }
}

然后:

calcs = new List<KeyValuePairDto<string, int>>
{
    new KeyValuePairDto<string, int> { Key = "TPrintBw", Value = gr.Sum(u => u.TPrintBw) },
    new KeyValuePairDto<string, int> { Key = "TPrintCol", Value = gr.Sum(u => u.TPrintCol) },
    new KeyValuePairDto<string, int> { Key = "TCopyBw", Value = gr.Sum(u => u.TCopyBw) },
    new KeyValuePairDto<string, int> { Key = "TCopyCol", Value = gr.Sum(u => u.TCopyCol) },
    new KeyValuePairDto<string, int> { Key = "TScan", Value = gr.Sum(u => u.TScan) },
    new KeyValuePairDto<string, int> { Key = "TFaxBw", Value = gr.Sum(u => u.TFaxBw) },
}

另一种方法是投射到匿名类型列表(通过数组初始化器与ToList结合使用),这是受支持的:

calcs = new []
{
    new { Key = "TPrintBw", Value = gr.Sum(u => u.TPrintBw) },
    new { Key = "TPrintCol", Value = gr.Sum(u => u.TPrintCol) },
    new { Key = "TCopyBw", Value = gr.Sum(u => u.TCopyBw) },
    new { Key = "TCopyCol", Value = gr.Sum(u => u.TCopyCol) },
    new { Key = "TScan", Value = gr.Sum(u => u.TScan) },
    new { Key = "TFaxBw", Value = gr.Sum(u => u.TFaxBw) },
}.ToList()