遍历列表,但无法访问不同的项目值

Iterating through a list, but can't access distinct item values

我正在使用 PDFsharp 创建发票。

这是我的 SQL table (tblTripsPerMonth):

我已将其绑定到 ObservableCollection (PaidTrips)。

目标是为 LicenseHolderID 列中每个不同的“CompanyName”创建一 (1) 个 PDF。 为此,我转换为 List,并按 LicenseHolderID.

分组
var paidTrips = PaidTrips
    .GroupBy(p => new {
        p.LicenseHolderID
})
.ToList();

之后,我用 foreach 循环遍历列表:

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
}

我能够创建一个 PDF 文档,每个不同的 LicenseHolderID,通过将 licenseHolderID 字符串添加到 PDFsharps document.Save() 的文件路径。

但是我无法用我需要的所有信息填写 PDF 文档。 我有汇总金额 - good,因为我绝对需要显示完整的发票金额。 但是——我还需要详细说明。我 没有 每个 VehicleID 的金额。

对于“CompanyName1”,将是 AG4203000002 和 AG4203000003,以及它们对应的行数据。

我确实这样做了...

IEnumerable<string> vehicleIds = trip
    .Select(x => x.VehicleID)
    .Distinct()
    .ToArray();
string vehicle = string.Join(", ", vehicleIds);

...为了将 VehicleID 个不同的值彼此分开。 然后我将 string vehicle 放入 PDFsharp 中,将文本绘制到 PDF (DrawString):

gfx.DrawString(vehicle, /* font and color customization */);

这为我提供了每个 LicenseHolderID 的正确数量的 VehicleID,但在一个长字符串中...不是最优的。

这让我想到了我的问题: A):我需要携带与VehicleID 中的不同车辆,以便我可以在我的 PDF 中填写详细信息,而不仅仅是汇总值,以及 B):如果 的解决方案A) 涉及摆脱又长又难懂的字符串 (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<IGrouping<string, PaidTrip>> does not contain a definition for 'Key' and no accessible extension method 'Key' accepting a first argument of type 'IEnumerable<IGrouping<string, PaidTrip>>' could be found (are you missing a using directive or an assembly reference?)

I need to bring along the row data of the other columns pertaining to the distinct vehicles in VehicleId, so that I can fill in details in my PDFs, and not just the summarized values.

如果我没理解错的话,对于每家公司 (LicenseHolderId),您需要他们的相关 Trip 对象,但按 VehicleId 分组 - 这很简单,只需添加另一个 GroupBy - 你可以在内部迭代它们 foreach:

List<Trip> paidTrips = ...

IEnumerable< IGrouping<String,Trip> > tripsGroupedByCompany = paidTrips.GroupBy( pt => pt.LicenseHolderId );

foreach( IGrouping<String,Trip> companyGroup in tripsGroupedByCompany )
{
    String licenseHolderId = companyGroup.Key;

    gfx.DrawString( "Company: " + licenseHolderId + "\r\n" );

    var groupedByVehicle = companyGroup.GroupBy( t => t.VehicleId );
    foreach( IGrouping<String,Trip> vehicleGroup in groupedByVehicle )
    {
        String vehicleId = vehicleGroup.Key;
        
        gfx.DrawString( "\tVehicle: " + vehicleId + "\r\n" );

        foreach( Trip trip in vehicleGroup )
        {
            gfx.DrawString( $"\t\tTrip: {trip.Year}-{trip.Month:00}. {trip.PaymentNet,11:C2}\r\n" );
        }
    }
}
  • 我添加了一些格式说明和字符,它们仅适用于文本模式(控制台应用程序),不适用于 PDF 渲染,但如果您好奇:

    • 我使用制表符 (\t) 来指示缩进,以便对相关数据进行视觉分组。
    • 我使用格式说明符 :00 来确保 Month 值显示为带前导零的 2 位数值。
    • 我使用格式说明符 ,11:C2 来确保 PaymentNet 值被格式化为带有 2 个小数位的货币值,并且始终左填充至至少 11 个字符宽度。
  • 这会给你这样的输出(如下)。

  • 请注意,虽然在您的源数据中每个 VehicleId 都只有一个与之关联的行程,但我上面的代码 允许 一个 VehicleId 以具有相同和不同 LicenseHolderId 值的多次行程,尽管下面的示例打印输出仅显示每辆车 1 次行程。

Company: CompanyName1
    Vehicle: AG4203000002
        Trip: 2021-07. 7,088.68

    Vehicle: AG4203000003
        Trip: 2021-07. 8,761.32

Company: CompanyName2:
    Vehicle: AG4203000004
        Trip: 2021-07. 9,264.15

    Vehicle: AG4203000005
        Trip: 2021-07.  ,273.58

但请注意,上面的代码很糟糕,因为它 交叉了关注点 (它做了 2 件不同的事情:它遍历了一个非平凡的对象图,并将数据呈现给您的PDF 库)。

更好的设计会分离图形遍历(可能是单个扩展方法)从而使 PDF 渲染代码更简单,但是我不能给你任何代码示例在不了解更多关于您的数据库设计和 if/how 您正在使用 EF 的情况下了解这一点。