【发布时间】:2021-11-21 18:38:46
【问题描述】:
我正在使用PDFsharp 创建发票。
这是我的 SQL 表 (tblTripsPerMonth):
我已将其绑定到 ObservableCollection (PaidTrips)。
目标是为LicenseHolderID 列中的每个不同的“公司名称”创建一 (1) 个 PDF。
为此,我转换为List,并按LicenseHolderID 分组。
var paidTrips = PaidTrips
.GroupBy(p => new {
p.LicenseHolderID
})
.ToList();
之后,我使用foreach-loop 遍历列表:
foreach (var trip in paidTrips) {
// I grab the distinct name
string licenseholder = trip.Key.LicenseHolderID.ToString();
// I summarize many of the columns
decimal totalPayment = trip.Sum(x => x.Payment);
decimal totalPaymentNet = trip.Sum(x => x.Payment);
decimal totalOrderFee = trip.Sum(x => x.Payment);
decimal totalPaymentFee = trip.Sum(x => x.Payment);
// I grab the first value of some other columns, which won't change
string licenseholderInvoiceID = trip.Select(x => x.LicenseHolderInvoiceID).FirstOrDefault().ToString();
string ridelRegionInvoiceID = trip.Select(x => x.RidelRegionInvoiceID ).FirstOrDefault().ToString();
// Creating PDF document using PDFsharp:
// PDFsharp code
// PDFsharp code
// PDFsharp code
}
通过将licenseHolderID-string 添加到 PDFsharps document.Save() 的文件路径中,我能够创建一个 PDF 文档,每个不同的 LicenseHolderID 一个。
但我无法在 PDF 文档中填写我需要的所有信息。
我有汇总金额 - 好,因为我绝对需要显示完整的发票金额。
但是——我还需要详细说明。我确实没有有每个VehicleID 的金额。
对于“CompanyName1”,应该是 AG4203000002 和 AG4203000003,以及它们对应的行数据。
我确实这样做了......
IEnumerable<string> vehicleIds = trip
.Select(x => x.VehicleID)
.Distinct()
.ToArray();
string vehicle = string.Join(", ", vehicleIds);
...为了将VehicleID 不同的值彼此分开。
然后我将string vehicle 放入PDFsharps 中,将文本绘制到PDF 上(DrawString):
gfx.DrawString(vehicle, /* font and color customization */);
这为每个LicenseHolderID 提供了正确数量的VehicleID,但在一个长字符串中...不是最佳的。
这让我想到了我的问题: A):我需要携带与VehicleID 中不同车辆相关的其他列的行数据,所以我可以在我的 PDF 中填写详细信息,而不仅仅是汇总值,以及 B):如果 A) 的解决方案涉及摆脱冗长的、hacky 字符串(vehicle),如果不是,那将是最佳选择 - 那也没关系。
更新(从@Dai 的回答中添加代码):
// PaidTrip = My holder class, which I've bound to a ObservableCollection (PaidTrips)
var paidTrips = PaidTrips.ToList(); // I was unsure about this one
IEnumerable<IGrouping<String, PaidTrip>> tripsGroupedByCompany = paidTrips.GroupBy(pt => pt.LicenseHolderID);
foreach (IGrouping<String, PaidTrip>> companyGroup in tripsGroupedByCompany) {
string licenseHolderId = companyGroup.Key;
gfx.DrawString(/* code goes foo */);
// I tried adding Key here, but that gave me a squiggly under "t.VehicleID"
var groupedByVehicle = companyGroup.GroupBy(t => t.VehicleID);
foreach (IGrouping<String, PaidTrip> vehicleGroup in groupedByVehicle) {
// This is where I get a red squiggly; under Key
String vehicleId = groupedByVehicle.Key;
gfx.DrawString(/* code goes foo */);
foreach (PaidTrip trip in vehicleGroup) {
gfx.DrawString(/* code goes foo */);
}
}
}
这是错误:
CS1061:IEnumerable
> 不包含“Key”的定义,并且没有可访问的扩展方法“Key”接受“IEnumerable >”类型的第一个参数找到(您是否缺少 using 指令或程序集引用?)
【问题讨论】:
-
这是在使用 WPF 的 交互式 桌面应用程序中,还是“无头”后台服务或 Web 应用程序?因为如果是后者,使用
ObservableCollection的理由为零。另外,为什么你的桌子有tbl前缀? (您应始终避免对数据库对象使用 Systems Hungarian Notation 前缀,否则当您将TABLE更改为VIEW或反之亦然时,您的系统最终看起来很傻,此外还有更多)。 -
提示:将
.GroupBy(p => new {p.LicenseHolderID } )更改为GroupBy( p => p.LicenseHolderID )。您不需要单成员匿名类,并且 (imo) 匿名类不应再使用,因为它们(通常,在大多数情况下)不如 ValueTuples。 -
你有没有正确配置的
DbContext可以用来直接查询Vehicles表等行程信息?您的tblTripsPerMonth表似乎是非规范化的(即设计不正确),因此您应该修复它... -
另一个提示:一般来说你不需要使用
ToArray,而是使用ToList(因为它在所有情况下都更快),如果你打算使用ToArray或@987654361 @ 然后将结果分别存储到T[]或List<T>,而不是IEnumerable<T>,因为当您使用IEnumerable<T>时,CLR 无法对List<T>和Array的成员进行快速非虚拟调用(例如,Linq 的.Count()扩展总是比List<T>.Count慢,有时甚至需要O(n)才能运行,eww)。 -
@DStanley 它 is 较慢:在 .NET 6 之前(或者可能是 .NET 7,如果它再次被踢),Linq
.Count()扩展都不是内联的,它只是检查IList<T>.Count和ICollection<T>.Count但不是IReadOnlyCollection<T>.Count(也不是IReadOnlyList<T>.Count),否则它将遍历整个集合以获取计数-这是因为在Linq 中检查IReadOnlyCollection也是相对 昂贵(见此线程:github.com/dotnet/runtime/issues/42254)另见本文:blog.slaks.net/2015-01-12/…
标签: c# list foreach ienumerable pdfsharp