Return 来自 linq2entities 的多维关联对象

Return a multidimensional associative object from linq2entities

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

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

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

我已经尝试了几次迭代,但无法进行以下工作。语法看起来是正确的,但现在(下面)我什至无法获得计数(任何),如果我只是将它分配为普通列表,我会得到一个行数,但我无法访问第二个 foreach 循环中的子对象.

那么是否有可能 return 来自 linq2sql 的混合 "sub object",如果不能,我的选择是什么?

  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();
    }

您的查询的问题是 LINQ to Entities 需要投影到具有无参数构造函数和 属性 setter 的类型,而 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()