通过列表循环 foreach,为不同的值执行代码
Looping with foreach through list, to execute code for distinct values
我正在尝试创建一个函数,为 List
中 属性 的每个 distinct 值创建一 (1) 个 PDF 发票正在循环(使用 PDFSharp)。
我获取 string
的值,并希望将其用作发票的抬头(这是开具发票的企业的名称)。
举例说明:
在下面table中,我想得到LicenseHolder1(一次)、LicenseHolder2(一次)和LicenseHolder3(一次)的值。
ID
LicenseHolderID
Value1
Value2
Value3
1
LicenseHolder1
66
44
UF-2107
2
LicenseHolder2
22
25
UF-2107
3
LicenseHolder2
62
24
UF-2107
4
LicenseHolder3
82
12
UF-2107
5
LicenseHolder3
6
77
UF-2107
6
LicenseHolder3
15
62
UF-2107
这是我正在使用的方法:
using (SqlConnection con = new(ConnectionString.connectionString))
using (SqlCommand cmd = new("spCreateInvoice", con) {CommandType = CommandType.StoredProcedure})
using (SqlDataAdapter da = new(cmd))
// this is the name of my SQL table
using (DataTable dt = new("tblTripsPerMonth"))
using (DataSet ds = new()) {
con.Open();
da.Fill(dt);
ds.Tables.Add(dt);
/* adding the SQL table rows to my ObservableCollection (PaidTrips),
which is bound to properties in my holder class (PaidTrip): */
foreach (DataRow dr in ds.Tables[0].Rows {
PaidTrips.Add(new PaidTrip {
LicenseHolderID = dr[0].ToString(),
Value1 = (decimal)dr[1],
Value2 = (decimal)dr[2],
Value3 = dr[3].ToString(),
});
// Now I am instantiating a list, so that I can group
List<PaidTrip> paidTrip = PaidTrips
.GroupBy(p => new {p.LicenseHolderID})
.Select(g => g.First())
.ToList();
// this is copied code from another question, and this is where I fall of
foreach (PaidTrip PaidTrips in paidTrip) {
foreach (var LicenseHolderID in PaidTrips.GetType().GetProperties()) {
string n = LicenseHolderID.GetValue(PaidTrips).ToString();
如果我在此之后抓取 string n
并将其传递给一个 MessageBox.Show
,它应该显示 LicenseHolder1
。
但是,如果我尝试将它传递到 PDF 中,就像这样......
(接上一个代码块)
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
PdfDocument pdf = new();
PdfPage page = pdf.AddPage();
XGraphics gfx = XGraphics.FromPdfPage(page);
// drawing in the string value
gfx.DrawString(n, new XFont("Arial", 40, XFontStyle.Bold), myColor, new XPoint(40, 250));
// saving the PDF
pdf.Save("C:\File\Path\TestPDF.pdf");
}
}
}
}
...创建了 PDF,但我绘制的字符串未填充 LicenseHolder1
,而是填充了其他列的(看似)随机值(如 66
、UF-2107
或 77
)。怎么会?
(哦,我知道这段代码只创建一 (1) 个 PDF 文件,我需要几个(LicenseHolderID
列中每个不同的值一个 - 但那是改天再说)
我认为您需要按 LicenseHolderID
分组,然后对其余字段求和/求最大值。从那里,您可以摆脱循环 foreach (var LicenseHolderID in PaidTrips.GetType().GetProperties())
,因为您将构建一个需要迭代的对象集合。
在您创建集合的位置,您可能希望在那里对数据进行分组,看起来您一次取一行:
var paidTrips = ds.Tables[0].Rows.Cast<DataRow>().GroupBy(t => t["LicenseHolderID"])
.Select(g => new PaidTrip {
LicenseHolderID = g.Key,
Value1 = g.Sum(x => x.["Value1"] ),
Value2 = g.Sum(x => x.["Value2"] ),
Value3 = g.Max(x => x.["Value3"] )
})
.ToList();
这应该会为您提供上面的列表,按 LicenseHolderID
分组,例如,LicenseHolder2 变为:
LicenseHolder2 84 49 UF-2107
鉴于您按 LicenseHolderID 分组。然后您可以迭代循环,在这种情况下获得 3 个 PDF。
foreach (PaidTrip pd in paidTrips ) {
string n = pd.LicenseHolderID;
//...pdf code...
gfx.DrawString(n, new XFont("Arial", 40, XFontStyle.Bold),
myColor, new XPoint(40, 250));
// saving the PDF
pdf.Save("C:\File\Path\TestPDF.pdf");
}
请注意,这是我手写的,所以它可能无法编译 - 但你应该明白了。
也许你可以这样做:
List<PaidTrip> paidTrip = PaidTrips
.GroupBy(p => new {p.LicenseHolderID})
.Select(g => g.First()).Distinct().ToList();
我不明白你试图在这些嵌套的 foreach 循环中完成什么
foreach (PaidTrip PaidTrips in paidTrip) {
foreach (var LicenseHolderID in PaidTrips.GetType().GetProperties()) {
//...
}
}
paidTrip
应该是一个 IEnumerable<PaidTrip>
代表每个公司的第一个 PaidTrip
,所以也许将变量重命名为 firstPaidTrips
将有助于澄清代码中的内容,那么你的外部 foreach 循环可能是
foreach (var paidTrip in firstPaidTrips)
那么就会更清楚那个foreach循环中的每个变量都是一个单一的paidTrip
要获得该付费旅行的 LicenseHolderID
,您只需直接访问 属性。
foreach (var paidTrip in firstPaidTrips)
{
var n = paidTrip.LicenseHolderID;
//rest of the code is the same without that inner foreach loop.
}
那个内部 foreach 循环看起来像是您在尝试使用反射来获取未知类型对象的所有属性,但是从您的示例代码看来您知道对象类型是什么,并且您应该能够只需从对象 PaidTrip
中获取 属性
您的数据表中是否有如上所示的 id 列?您的零列不会在那里取一个 ID 吗?
foreach (DataRow dr in ds.Tables[0].Rows {
PaidTrips.Add(new PaidTrip {
LicenseHolderID = dr[0].ToString(),
Value1 = (decimal)dr[1],
Value2 = (decimal)dr[2],
Value3 = dr[3].ToString(),
});
如果您按 LicenseHolderID 分组,则选择分组结果的第一个元素。这是故意的吗?
List<PaidTrip> paidTrip = PaidTrips
.GroupBy(p => new {p.LicenseHolderID})
.Select(g => g.First())
.ToList();
这将本质上 return 一个包含多个包含相同 LicenseHolderID 的付费旅行对象的新对象。
通常如果你想使用组的字符串名称,你可以引用键值。
paidTrip.Key.ToString();
可能更好用,
var paidTrip = PaidTrips
.GroupBy(p => new {p.LicenseHolderID})
.ToList();
foreach (var tripFound in paidTrip)
{
string tripId = tripFound.Key.ToString();
//Generate your PDF File.
}
这应该为每个组提供一个文件。如果我误会了你,我深表歉意。
我正在尝试创建一个函数,为 List
中 属性 的每个 distinct 值创建一 (1) 个 PDF 发票正在循环(使用 PDFSharp)。
我获取 string
的值,并希望将其用作发票的抬头(这是开具发票的企业的名称)。
举例说明: 在下面table中,我想得到LicenseHolder1(一次)、LicenseHolder2(一次)和LicenseHolder3(一次)的值。
ID | LicenseHolderID | Value1 | Value2 | Value3 |
---|---|---|---|---|
1 | LicenseHolder1 | 66 | 44 | UF-2107 |
2 | LicenseHolder2 | 22 | 25 | UF-2107 |
3 | LicenseHolder2 | 62 | 24 | UF-2107 |
4 | LicenseHolder3 | 82 | 12 | UF-2107 |
5 | LicenseHolder3 | 6 | 77 | UF-2107 |
6 | LicenseHolder3 | 15 | 62 | UF-2107 |
这是我正在使用的方法:
using (SqlConnection con = new(ConnectionString.connectionString))
using (SqlCommand cmd = new("spCreateInvoice", con) {CommandType = CommandType.StoredProcedure})
using (SqlDataAdapter da = new(cmd))
// this is the name of my SQL table
using (DataTable dt = new("tblTripsPerMonth"))
using (DataSet ds = new()) {
con.Open();
da.Fill(dt);
ds.Tables.Add(dt);
/* adding the SQL table rows to my ObservableCollection (PaidTrips),
which is bound to properties in my holder class (PaidTrip): */
foreach (DataRow dr in ds.Tables[0].Rows {
PaidTrips.Add(new PaidTrip {
LicenseHolderID = dr[0].ToString(),
Value1 = (decimal)dr[1],
Value2 = (decimal)dr[2],
Value3 = dr[3].ToString(),
});
// Now I am instantiating a list, so that I can group
List<PaidTrip> paidTrip = PaidTrips
.GroupBy(p => new {p.LicenseHolderID})
.Select(g => g.First())
.ToList();
// this is copied code from another question, and this is where I fall of
foreach (PaidTrip PaidTrips in paidTrip) {
foreach (var LicenseHolderID in PaidTrips.GetType().GetProperties()) {
string n = LicenseHolderID.GetValue(PaidTrips).ToString();
如果我在此之后抓取 string n
并将其传递给一个 MessageBox.Show
,它应该显示 LicenseHolder1
。
但是,如果我尝试将它传递到 PDF 中,就像这样......
(接上一个代码块)
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
PdfDocument pdf = new();
PdfPage page = pdf.AddPage();
XGraphics gfx = XGraphics.FromPdfPage(page);
// drawing in the string value
gfx.DrawString(n, new XFont("Arial", 40, XFontStyle.Bold), myColor, new XPoint(40, 250));
// saving the PDF
pdf.Save("C:\File\Path\TestPDF.pdf");
}
}
}
}
...创建了 PDF,但我绘制的字符串未填充 LicenseHolder1
,而是填充了其他列的(看似)随机值(如 66
、UF-2107
或 77
)。怎么会?
(哦,我知道这段代码只创建一 (1) 个 PDF 文件,我需要几个(LicenseHolderID
列中每个不同的值一个 - 但那是改天再说)
我认为您需要按 LicenseHolderID
分组,然后对其余字段求和/求最大值。从那里,您可以摆脱循环 foreach (var LicenseHolderID in PaidTrips.GetType().GetProperties())
,因为您将构建一个需要迭代的对象集合。
在您创建集合的位置,您可能希望在那里对数据进行分组,看起来您一次取一行:
var paidTrips = ds.Tables[0].Rows.Cast<DataRow>().GroupBy(t => t["LicenseHolderID"])
.Select(g => new PaidTrip {
LicenseHolderID = g.Key,
Value1 = g.Sum(x => x.["Value1"] ),
Value2 = g.Sum(x => x.["Value2"] ),
Value3 = g.Max(x => x.["Value3"] )
})
.ToList();
这应该会为您提供上面的列表,按 LicenseHolderID
分组,例如,LicenseHolder2 变为:
LicenseHolder2 84 49 UF-2107
鉴于您按 LicenseHolderID 分组。然后您可以迭代循环,在这种情况下获得 3 个 PDF。
foreach (PaidTrip pd in paidTrips ) {
string n = pd.LicenseHolderID;
//...pdf code...
gfx.DrawString(n, new XFont("Arial", 40, XFontStyle.Bold),
myColor, new XPoint(40, 250));
// saving the PDF
pdf.Save("C:\File\Path\TestPDF.pdf");
}
请注意,这是我手写的,所以它可能无法编译 - 但你应该明白了。
也许你可以这样做:
List<PaidTrip> paidTrip = PaidTrips
.GroupBy(p => new {p.LicenseHolderID})
.Select(g => g.First()).Distinct().ToList();
我不明白你试图在这些嵌套的 foreach 循环中完成什么
foreach (PaidTrip PaidTrips in paidTrip) {
foreach (var LicenseHolderID in PaidTrips.GetType().GetProperties()) {
//...
}
}
paidTrip
应该是一个 IEnumerable<PaidTrip>
代表每个公司的第一个 PaidTrip
,所以也许将变量重命名为 firstPaidTrips
将有助于澄清代码中的内容,那么你的外部 foreach 循环可能是
foreach (var paidTrip in firstPaidTrips)
那么就会更清楚那个foreach循环中的每个变量都是一个单一的paidTrip
要获得该付费旅行的 LicenseHolderID
,您只需直接访问 属性。
foreach (var paidTrip in firstPaidTrips)
{
var n = paidTrip.LicenseHolderID;
//rest of the code is the same without that inner foreach loop.
}
那个内部 foreach 循环看起来像是您在尝试使用反射来获取未知类型对象的所有属性,但是从您的示例代码看来您知道对象类型是什么,并且您应该能够只需从对象 PaidTrip
您的数据表中是否有如上所示的 id 列?您的零列不会在那里取一个 ID 吗?
foreach (DataRow dr in ds.Tables[0].Rows {
PaidTrips.Add(new PaidTrip {
LicenseHolderID = dr[0].ToString(),
Value1 = (decimal)dr[1],
Value2 = (decimal)dr[2],
Value3 = dr[3].ToString(),
});
如果您按 LicenseHolderID 分组,则选择分组结果的第一个元素。这是故意的吗?
List<PaidTrip> paidTrip = PaidTrips
.GroupBy(p => new {p.LicenseHolderID})
.Select(g => g.First())
.ToList();
这将本质上 return 一个包含多个包含相同 LicenseHolderID 的付费旅行对象的新对象。
通常如果你想使用组的字符串名称,你可以引用键值。
paidTrip.Key.ToString();
可能更好用,
var paidTrip = PaidTrips
.GroupBy(p => new {p.LicenseHolderID})
.ToList();
foreach (var tripFound in paidTrip)
{
string tripId = tripFound.Key.ToString();
//Generate your PDF File.
}
这应该为每个组提供一个文件。如果我误会了你,我深表歉意。