C# 如何使用datatable中的关系填充对象?
我在设计将CSV中的数据转换为业务对象的方法时遇到困难。我首先解析CSV并将每一行放入一个数据表,这就是我的思维块开始的地方 我有以下几个类,其中APDistribution被视为具有1:Many关系的凭证的子类:C# 如何使用datatable中的关系填充对象?,c#,linq,C#,Linq,我在设计将CSV中的数据转换为业务对象的方法时遇到困难。我首先解析CSV并将每一行放入一个数据表,这就是我的思维块开始的地方 我有以下几个类,其中APDistribution被视为具有1:Many关系的凭证的子类: public class Voucher { public string GPVoucherNumber { get; set; } public string VendorID { get; set; } public string TransactionD
public class Voucher
{
public string GPVoucherNumber { get; set; }
public string VendorID { get; set; }
public string TransactionDescription { get; set; }
public string Title { get; set; }
public string DocNumber { get; set; }
public DateTime DocDate { get; set; }
public decimal PurchaseAmount { get; set; }
public IEnumerable<APDistribution> Distributions { get; set; }
}
public class APDistribution
{
public string AccountNumber { get; set; }
public decimal Debit { get; set; }
public decimal Credit { get; set; }
public string DistributionReference { get; set; }
}
公共类凭证
{
公共字符串GPVoucherNumber{get;set;}
公共字符串VendorID{get;set;}
公共字符串TransactionDescription{get;set;}
公共字符串标题{get;set;}
公共字符串DocNumber{get;set;}
公共日期时间DocDate{get;set;}
公共十进制购买金额{get;set;}
公共数字
我一开始认为我可以使用Linq来投影到我的业务对象上,但我不知道如何构造查询来一次性完成。我发现自己在想,我是否可以执行一个查询来投影到凭证集合,一个查询来投影到APDistribution集合,然后执行某种代码来正确关联它们
我从以下内容开始,按照字段进行分组,这些字段应该唯一地定义凭证,但这不起作用,因为投影处理的是匿名类型,而不是DataRow
var vouchers =
from row in invoicesTable.AsEnumerable()
group row by new { vendor = row.Field<string>("Vendor Code"), invoice = row.Field<string>("Vendor Invoice Number") } into rowGroup
select new Voucher
{ VendorID = rowGroup.Field<string>("Vendor Code") };
var凭证=
来自invoicesTable.AsEnumerable()中的行
按新的{vendor=row.Field(“vendor Code”)、invoice=row.Field(“vendor invoice Number”)}将行分组到rowGroup中
选择新凭证
{VendorID=rowGroup.Field(“供应商代码”)};
这是否可以在不引入复杂Linq的情况下实现,而未来的开发人员(包括我自己)可能很难理解/维护复杂Linq?是否有一种没有Linq的更简单方法,我忽略了它?总体思路是:
invoicesTable
.AsEnumerable()
.GroupBy(x=> new { row.Field<string>("Vendor Code"), row.Field<string>("Vendor Invoice Number")})
.Select(grouping =>
new Voucher
{
VendorID = grouping.First().Field<string>("VendorId") /* and so on */
Distributions = grouping.Select(somerow => new redistribution {AccountNumber = somerow.Field<string>("AccountNumber") /* and so on */}
}
invoicesTable
.可计算的()
.GroupBy(x=>new{row.Field(“供应商代码”)、row.Field(“供应商发票号”)})
.选择(分组=>
新凭证
{
VendorID=grouping.First().Field(“VendorID”)/*等等*/
Distributions=grouping.Select(somerow=>new再分配{AccountNumber=somerow.Field(“AccountNumber”)/*等等*/}
}
但这不是最优雅的方式。总体思路是:
invoicesTable
.AsEnumerable()
.GroupBy(x=> new { row.Field<string>("Vendor Code"), row.Field<string>("Vendor Invoice Number")})
.Select(grouping =>
new Voucher
{
VendorID = grouping.First().Field<string>("VendorId") /* and so on */
Distributions = grouping.Select(somerow => new redistribution {AccountNumber = somerow.Field<string>("AccountNumber") /* and so on */}
}
invoicesTable
.可计算的()
.GroupBy(x=>new{row.Field(“供应商代码”)、row.Field(“供应商发票号”)})
.选择(分组=>
新凭证
{
VendorID=grouping.First().Field(“VendorID”)/*等等*/
Distributions=grouping.Select(somerow=>new再分配{AccountNumber=somerow.Field(“AccountNumber”)/*等等*/}
}
但这并不是最优雅的方式。虽然Linq很酷,可以提高效率,但如果您今天不能确定代码是否正确,明天也无法理解代码,那么它就不会增加价值。在这种情况下,使用Linq可能是一种错误
从一个非Linq解决方案开始,该解决方案可验证准确,而不会毫无必要地低效,然后在性能出现问题时进行优化
以下是我如何解决这个问题:
var vouchers = new Dictionary<string, Voucher>();
foreach (DataRow row in invoicesTable)
{
string vendor = row.Field<string>("Vendor Code");
string invoice = row.Field<string>("Vendor Invoice Number");
string voucherKey = vendor + "|" + invoice;
if (!vouchers.ContainsKey(voucherKey))
{
vouchers.Add(voucherKey, new Voucher { VendorID = vendor, DocNumber = invoice });
}
vouchers[voucherKey].Distributions.Add(new APDistribution { AccountNumber = row.Field<string>("Journal Account Code") });
}
var凭证=新字典();
foreach(invoicesTable中的数据行)
{
字符串vendor=行字段(“vendor Code”);
字符串发票=行字段(“供应商发票编号”);
字符串voucherKey=供应商+“|”+发票;
如果(!凭证.ContainsKey(凭证键))
{
添加(voucherKey,新凭证{VendorID=vendor,DocNumber=invoice});
}
凭证[voucherKey].Distributions.Add(新的APDistribution{AccountNumber=row.Field(“日记账科目代码”)});
}
如果这将处理大量行,您可以通过将字典预分配到唯一供应商数量的估计值来对此进行调整:
var vouchers = new Dictionary<string, Voucher>(invoicesTable.Rows.Count * 0.8);
var凭证=新字典(invoicesTable.Rows.Count*0.8);
虽然Linq很酷,可以提高效率,但如果您今天不能确定代码是否正确,明天也无法理解代码,那么它就不会增加价值。在这种情况下,使用Linq可能是一种错误
从一个非Linq解决方案开始,该解决方案可验证准确,而不会毫无必要地低效,然后在性能出现问题时进行优化
以下是我如何解决这个问题:
var vouchers = new Dictionary<string, Voucher>();
foreach (DataRow row in invoicesTable)
{
string vendor = row.Field<string>("Vendor Code");
string invoice = row.Field<string>("Vendor Invoice Number");
string voucherKey = vendor + "|" + invoice;
if (!vouchers.ContainsKey(voucherKey))
{
vouchers.Add(voucherKey, new Voucher { VendorID = vendor, DocNumber = invoice });
}
vouchers[voucherKey].Distributions.Add(new APDistribution { AccountNumber = row.Field<string>("Journal Account Code") });
}
var凭证=新字典();
foreach(invoicesTable中的数据行)
{
字符串vendor=行字段(“vendor Code”);
字符串发票=行字段(“供应商发票编号”);
字符串voucherKey=供应商+“|”+发票;
如果(!凭证.ContainsKey(凭证键))
{
添加(voucherKey,新凭证{VendorID=vendor,DocNumber=invoice});
}
凭证[voucherKey].Distributions.Add(新的APDistribution{AccountNumber=row.Field(“日记账科目代码”)});
}
如果这将处理大量行,您可以通过将字典预分配到唯一供应商数量的估计值来对此进行调整:
var vouchers = new Dictionary<string, Voucher>(invoicesTable.Rows.Count * 0.8);
var凭证=新字典(invoicesTable.Rows.Count*0.8);
您正在寻找Linq连接。以获得更大的深度
然而,您似乎遇到了麻烦,这是因为在您的2个对象上,您需要对查询进行比较,比如添加公共字符串VendorID{get;set;}
到APDistribution
类,如果可能的话。我会假设CSV文件将APDistribution
绑定回凭证
,所以不管它是什么,确保它在两个类中都存在,这样你就可以将一个类与另一个类关联起来。两个类中的名称不需要相同,但应该是.M更重要的是,您现在有了一个等式比较器可以用于连接操作的东西
就我个人而言,如果我能把它们分开,让事情变得更简单,我就不喜欢大而粗糙的查询。太多的事情不可能一下子全部讲清楚,而你已经做到了