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()
免责声明:第一个 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()