LINQ To Objects - 加入空列表
Posted
技术标签:
【中文标题】LINQ To Objects - 加入空列表【英文标题】:LINQ To Objects - Join on empty list 【发布时间】:2017-12-25 09:03:54 【问题描述】:我有三个从不同数据源填充的单独列表,现在我想将它们加入到 LINQ 语句中以获得最终结果。但是,完全有可能其中一个列表可能是空的。如果列表为空,我似乎不能只编写一个 LINQ 语句来加入其中的任何一个。
我已经编写了以下测试。我得到的错误是“NullReferenceException:对象引用未设置为对象的实例。”
// these colloections emulate the table structures and data
List<Agent> agents = new List<Agent>();
agents.Add(new Agent AgentId = 1, ClientId = 11 );
agents.Add(new Agent AgentId = 1, ClientId = 12 );
agents.Add(new Agent AgentId = 1, ClientId = 13 );
agents.Add(new Agent AgentId = 1, ClientId = 14 );
agents.Add(new Agent AgentId = 2, ClientId = 21 );
agents.Add(new Agent AgentId = 2, ClientId = 22 );
agents.Add(new Agent AgentId = 3, ClientId = 31 );
List<Client> clients = new List<Client>();
clients.Add(new Client ClientId = 11, ClientName = "A Client 11", Status = "A" );
clients.Add(new Client ClientId = 12, ClientName = "A Client 12", Status = "A" );
clients.Add(new Client ClientId = 13, ClientName = "A Client 13", Status = "A" );
clients.Add(new Client ClientId = 14, ClientName = "A Client 14", Status = "A" );
clients.Add(new Client ClientId = 21, ClientName = "A Client 21", Status = "A" );
clients.Add(new Client ClientId = 22, ClientName = "A Client 22", Status = "A" );
clients.Add(new Client ClientId = 31, ClientName = "A Client 31", Status = "A" );
// Upon initilization, there are no records here. Eventually, this "table" will be populated,
// but only after the user has used the app for a while. If I populate this list, it works assuming
// the agent ID I'm looking for is in the collection. But if it's not the join fails
List<ClientAdminFee> adminFees = new List<ClientAdminFee>();
// adminFees.Add(new ClientAdminFee AgentId = 1, ClientId = 11, AdminFee = 0.05m, EffectiveFrom = DateTime.Parse("2017-01-01") );
// adminFees.Add(new ClientAdminFee AgentId = 1, ClientId = 12, AdminFee = 0.05m, EffectiveFrom = DateTime.Parse("2017-01-01") );
// adminFees.Add(new ClientAdminFee AgentId = 1, ClientId = 13, AdminFee = 0.05m, EffectiveFrom = DateTime.Parse("2017-01-01") );
// adminFees.Add(new ClientAdminFee AgentId = 1, ClientId = 14, AdminFee = 0.05m, EffectiveFrom = DateTime.Parse("2017-01-01") );
var thisAgent = 1;
var theseAgents = agents.Where(x => x.AgentId == thisAgent).ToList();
var theseClients = clients.ToList();
var theseAdminFees = adminFees.Where(x => x.AgentId == thisAgent).ToList();
var final = (from ar in theseAgents
join c in theseClients on ar.ClientId equals c.ClientId
join caf in theseAdminFees on new ar.AgentId, c.ClientId equals new caf.AgentId, caf.ClientId into d
from caf in d.DefaultIfEmpty()
select new ClientWithAdminFee
AgentId = Convert.ToInt32(ar.AgentId),
ClientId = Convert.ToInt32(c.ClientId),
ClientName = c.ClientName,
Status = c.Status,
AdminFee = caf.AdminFee ?? 0.00m,
EffectiveDate = caf.EffectiveFrom ?? DateTime.Now
).ToList();
final.Dump();
正如我所说,如果我取消注释 adminFees 条目并搜索 AgentId 1,它就可以工作。但是,如果我搜索不在该集合中的代理,我根本无法进行加入。那么,如果有条目以及没有条目,我该如何编写它才能正常工作。
【问题讨论】:
查看左外连接。见 msdn:code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b 代码似乎用DefaultIfEmpty
明确要求空值 - 所以你最好处理它。旁注:你不能在 empty list 上获得 NRE,因为它本身不为 null...
我一直在做 LEFT OUTER JOINS,并且知道它是如何工作的。在这种情况下,它并没有真正帮助我。如果我在 LINQ 语句之前检查集合是否为空,那么我不能很好地编写适用于任何一种情况的 LINQ 语句。
如果您有 LINQPad,并将此代码复制到其中并运行它,您将看到问题。然后,如果您取消注释到 adminfees 集合中的条目,然后重新运行它,您会看到它有效。应用程序需要能够处理这两种情况,我不知道如何继续。同样,这不是 LEFT OUTER JOIN 的问题,因为我一直都在这样做。
【参考方案1】:
试试这个
var final = (from ar in theseAgents
join c in theseClients on ar.ClientId equals c.ClientId
join caf in theseAdminFees on new ar.AgentId, c.ClientId equals new caf.AgentId, caf.ClientId into d
from caf in d.DefaultIfEmpty()
select new ClientWithAdminFee
AgentId = Convert.ToInt32(ar.AgentId),
ClientId = Convert.ToInt32(c.ClientId),
ClientName = c.ClientName,
Status = c.Status,
AdminFee = caf != null ? (caf.AdminFee) : 0,
EffectiveDate = caf != null ? (caf.EffectiveFrom == null ? DateTime.Now : caf.EffectiveFrom) : DateTime.Now,
).ToList();
【讨论】:
谢谢,大部分工作。我不得不更改我的基础对象 (ClientWithAdminFee) 以包含 Nullable 属性,但它起作用了。再次感谢您,我知道这可能是我忽略了一些简单的事情。以上是关于LINQ To Objects - 加入空列表的主要内容,如果未能解决你的问题,请参考以下文章