Linq 左外连接 C#
Linq Left Outer Join C#
我使用这个 linq 查询已有一段时间了。我看过很多关于 Whosebug 及其他方面的答案。我尝试了很多解决方案并阅读了同样多的内容。下面的代码是我尝试创建此内部连接的多次尝试中的 2 次,我得到的错误是
Object reference not set to an instance of the object
尝试 A
var records = from cr in lstContactResponse
join jn in lstJourneyNodeData on cr.GrandparentId equals jn.Id into a
from x in a.DefaultIfEmpty()
join j in lstJourney on x.JourneyId equals j.Id into b
from y in b.DefaultIfEmpty()
join ce in lstCampaignElement on y.Name equals ce.LinkedJourney into c
from z in c.DefaultIfEmpty()
join c in lstCampaign on z.CampaignId equals c.Id into d
from w in d.DefaultIfEmpty()
select new JourneyRecord
{
CompanyName = w.Company,
BrandName = w.Brand,
CampaignName = w.Name,
Channel = z.Type,
Wave = "",
CampaignId = w.Id,
ActivityDate = cr.ResponseDate,
Activity = "",
Unsubscribed = cr.Unsubscribed,
Responded = cr.Responded,
Clicked = cr.Clicked,
Viewed = cr.Viewed,
Sent = cr.Sent,
Targeted = cr.Targeted,
HardBounced = cr.HardBounced,
SoftBounced = cr.SoftBounced,
WasTargeted = cr.WasTargeted,
Email = "",
Id = "",
CampaignElementId = z.Id,
CampaignWaveId = "J" + x.Id,
ContactId = cr.ContactId,
AtTaskId = w.AtTaskId,
LinkClicked = cr.Referrer,
OptTopic = z.TopicId,
DiseaseState = "",
ElementDescription = y.Name,
WaveDescription = x.Label
};
尝试 B
var records = from cr in lstContactResponse
join jn in lstJourneyNodeData on cr.GrandparentId equals jn.Id into a
from x in a.DefaultIfEmpty()
join j in lstJourney on x.JourneyId equals j.Id into b
from y in b.DefaultIfEmpty()
join ce in lstCampaignElement on y.Name equals ce.LinkedJourney into c
from z in c.DefaultIfEmpty()
join c in lstCampaign on z.CampaignId equals c.Id into d
from w in d.DefaultIfEmpty()
select new JourneyRecord
{
CompanyName = x == null ? null : w.Company,
BrandName = x == null ? null : w.Brand,
CampaignName = x == null ? null : w.Name,
Channel = x == null ? null : z.Type,
Wave = "",
CampaignId = x == null ? null : w.Id,
ActivityDate = x == null ? null : cr.ResponseDate,
Activity = "",
Unsubscribed = x == null ? null : cr.Unsubscribed,
Responded = x == null ? null : cr.Responded,
Clicked = x == null ? null : cr.Clicked,
Viewed = x == null ? null : cr.Viewed,
Sent = x == null ? null : cr.Sent,
Targeted = x == null ? null : cr.Targeted,
HardBounced = x == null ? null : cr.HardBounced,
SoftBounced = x == null ? null : cr.SoftBounced,
WasTargeted = x == null ? null : cr.WasTargeted,
Email = "",
Id = "",
CampaignElementId = x == null ? null : z.Id,
CampaignWaveId = "J" + (x == null ? null : x.Id),
ContactId = x == null ? null : cr.ContactId,
AtTaskId = x == null ? null : w.AtTaskId,
LinkClicked = x == null ? null : cr.Referrer,
OptTopic = x == null ? null : z.TopicId,
DiseaseState = "",
ElementDescription = x == null ? null : y.Name,
WaveDescription = x == null ? null : x.Label
};
尝试 C
var records = from cr in lstContactResponse
join jn in lstJourneyNodeData on cr.GrandparentId equals jn.Id into a
from x in a.DefaultIfEmpty()
join j in lstJourney on x.JourneyId equals j.Id into b
from y in b.DefaultIfEmpty()
join ce in lstCampaignElement on y.Name equals ce.LinkedJourney into c
from z in c.DefaultIfEmpty()
join c in lstCampaign on z.CampaignId equals c.Id into d
from w in d.DefaultIfEmpty()
select new JourneyRecord
{
CompanyName = w == null ? null : w.Company,
BrandName = w == null ? null : w.Brand,
CampaignName = w == null ? null : w.Name,
Channel = z == null ? null : z.Type,
Wave = "",
CampaignId = w == null ? null : w.Id,
ActivityDate = cr == null ? null : cr.ResponseDate,
Activity = "",
Unsubscribed = cr == null ? null : cr.Unsubscribed,
Responded = cr == null ? null : cr.Responded,
Clicked = cr == null ? null : cr.Clicked,
Viewed = cr == null ? null : cr.Viewed,
Sent = cr == null ? null : cr.Sent,
Targeted = cr == null ? null : cr.Targeted,
HardBounced = cr == null ? null : cr.HardBounced,
SoftBounced = cr == null ? null : cr.SoftBounced,
WasTargeted = cr == null ? null : cr.WasTargeted,
Email = "",
Id = "",
CampaignElementId = z == null ? null : z.Id,
CampaignWaveId = "J" + (x == null ? null : x.Id),
ContactId = cr == null ? null : cr.ContactId,
AtTaskId = w == null ? null : w.AtTaskId,
LinkClicked = cr == null ? null : cr.Referrer,
OptTopic = z == null ? null : z.TopicId,
DiseaseState = "",
ElementDescription = y == null ? null : y.Name,
WaveDescription = x == null ? null : x.Label
};
我无法通过 Linq 确定完成我想做的事情。因此,我转向了另一个方向来解决问题。
foreach (ContactResponse cr in lstContactResponse)
{
ContactResponseRecord crr = new ContactResponseRecord() {
ContactId = cr.ContactId,
ActivityDate = cr.ResponseDate,
LinkClicked = cr.Referrer};
var vJourneyNodeData = from x in lstJourneyNodeData where x.Id == cr.GrandparentId select x;
if(null != vJourneyNodeData && vJourneyNodeData.Count() > 0)
{
jnd = vJourneyNodeData.FirstOrDefault();
crr.CampaignWaveId = "J" + jnd.Id;
crr.WaveDescription = jnd.Label;
}
var vJourney = from x in lstJourney where x.Id == jnd.JourneyId select x;
if (null != vJourney && vJourney.Count() > 0)
{
j = vJourney.FirstOrDefault();
crr.OptTopic = j.TopicId;
}
var vCampaignElement = from x in lstCampaignElement where x.LinkedJourney == j.Name select x;
if (null != vCampaignElement && vCampaignElement.Count() > 0)
{
ce = vCampaignElement.FirstOrDefault();
crr.Ccg_Id = ce.CCGId;
crr.ElementDescription = ce.Description.ToString();
crr.CampaignElementId = ce.Id;
var vCampaign = from x in lstCampaign where x.Id == ce.CampaignId select x;
if (null != vCampaign && vCampaign.Count() > 0)
{
c = vCampaign.FirstOrDefault();
crr.ActivityDate = c.AtTaskId;
crr.BrandName = c.Brand;
crr.CampaignId = c.Id;
crr.CampaignName = c.Name;
crr.CompanyName = c.Company;
}
}
当然,在 LINQ 中有一种方法可以做到这一点。如果您在评论中回答了我的问题,我会为您提供确切的解决方案,现在我只举一个例子。 LINQ to Objects 与 LINQ to Entities 的技术不同,因此以下内容适用于 LINQ to Objects。
解决方案是检查左连接右侧涉及的每个 null
属性,包括 进一步的连接。值类型属性也需要转换为可为空的(这就是为什么 类 对于之前的 C#6 代码很重要)。
示例如下:
有以下"tables"
var t1 = new[]
{
new { Id = 1 , Name = "A", Date = DateTime.Today },
new { Id = 2 , Name = "B", Date = DateTime.Today},
new { Id = 3 , Name = "C", Date = DateTime.Today},
};
var t2 = new[]
{
new { Id = 1 , ParentId = 1, Name = "A1", Date = DateTime.Today },
new { Id = 2 , ParentId = 2, Name = "B1", Date = DateTime.Today },
};
var t3 = new[]
{
new { Id = 1 , ParentId = 1, Name = "A11", Date = DateTime.Today },
new { Id = 2 , ParentId = 1, Name = "A12", Date = DateTime.Today },
};
var t4 = new[]
{
new { Id = 1 , ParentId = 1, Name = "A111", Date = DateTime.Today },
};
C#6 之前版本
var query =
from e1 in t1
join e2 in t2 on e1.Id equals e2.ParentId into g2
from e2 in g2.DefaultIfEmpty()
join e3 in t3 on e2 != null ? (int?)e2.Id : null equals e3.ParentId into g3
from e3 in g3.DefaultIfEmpty()
join e4 in t4 on e3 != null ? (int?)e3.Id : null equals e4.Id into g4
from e4 in g4.DefaultIfEmpty()
select new
{
t1_Id = e1.Id,
t1_Name = e1.Name,
t1_Date = e1.Date,
t2_Id = e2 != null ? (int?)e2.Id : null,
t2_Name = e2 != null ? e2.Name : null,
t2_Date = e2 != null ? (DateTime?)e2.Date : null,
t3_Id = e3 != null ? (int?)e3.Id : null,
t3_Name = e3 != null ? e3.Name : null,
t3_Date = e3 != null ? (DateTime?)e3.Date : null,
t4_Id = e4 != null ? (int?)e4.Id : null,
t4_Name = e4 != null ? e4.Name : null,
t4_Date = e4 != null ? (DateTime?)e4.Date : null,
};
var result = query.ToList();
看起来很丑,但是很管用。
C#6 - 只需在任何右侧 属性 访问器之前添加 ?
即可获得相同的结果(重复 - 包括个加入条件)
var query =
from e1 in t1
join e2 in t2 on e1.Id equals e2.ParentId into g2
from e2 in g2.DefaultIfEmpty()
join e3 in t3 on e2?.Id equals e3.ParentId into g3
from e3 in g3.DefaultIfEmpty()
join e4 in t4 on e3?.Id equals e4.Id into g4
from e4 in g4.DefaultIfEmpty()
select new
{
t1_Id = e1.Id,
t1_Name = e1.Name,
t1_Date = e1.Date,
t2_Id = e2?.Id,
t2_Name = e2?.Name,
t2_Date = e2?.Date,
t3_Id = e3?.Id,
t3_Name = e3?.Name,
t3_Date = e3?.Date,
t4_Id = e4?.Id,
t4_Name = e4?.Name,
t4_Date = e4?.Date,
};
var result = query.ToList();
我使用这个 linq 查询已有一段时间了。我看过很多关于 Whosebug 及其他方面的答案。我尝试了很多解决方案并阅读了同样多的内容。下面的代码是我尝试创建此内部连接的多次尝试中的 2 次,我得到的错误是
Object reference not set to an instance of the object
尝试 A
var records = from cr in lstContactResponse
join jn in lstJourneyNodeData on cr.GrandparentId equals jn.Id into a
from x in a.DefaultIfEmpty()
join j in lstJourney on x.JourneyId equals j.Id into b
from y in b.DefaultIfEmpty()
join ce in lstCampaignElement on y.Name equals ce.LinkedJourney into c
from z in c.DefaultIfEmpty()
join c in lstCampaign on z.CampaignId equals c.Id into d
from w in d.DefaultIfEmpty()
select new JourneyRecord
{
CompanyName = w.Company,
BrandName = w.Brand,
CampaignName = w.Name,
Channel = z.Type,
Wave = "",
CampaignId = w.Id,
ActivityDate = cr.ResponseDate,
Activity = "",
Unsubscribed = cr.Unsubscribed,
Responded = cr.Responded,
Clicked = cr.Clicked,
Viewed = cr.Viewed,
Sent = cr.Sent,
Targeted = cr.Targeted,
HardBounced = cr.HardBounced,
SoftBounced = cr.SoftBounced,
WasTargeted = cr.WasTargeted,
Email = "",
Id = "",
CampaignElementId = z.Id,
CampaignWaveId = "J" + x.Id,
ContactId = cr.ContactId,
AtTaskId = w.AtTaskId,
LinkClicked = cr.Referrer,
OptTopic = z.TopicId,
DiseaseState = "",
ElementDescription = y.Name,
WaveDescription = x.Label
};
尝试 B
var records = from cr in lstContactResponse
join jn in lstJourneyNodeData on cr.GrandparentId equals jn.Id into a
from x in a.DefaultIfEmpty()
join j in lstJourney on x.JourneyId equals j.Id into b
from y in b.DefaultIfEmpty()
join ce in lstCampaignElement on y.Name equals ce.LinkedJourney into c
from z in c.DefaultIfEmpty()
join c in lstCampaign on z.CampaignId equals c.Id into d
from w in d.DefaultIfEmpty()
select new JourneyRecord
{
CompanyName = x == null ? null : w.Company,
BrandName = x == null ? null : w.Brand,
CampaignName = x == null ? null : w.Name,
Channel = x == null ? null : z.Type,
Wave = "",
CampaignId = x == null ? null : w.Id,
ActivityDate = x == null ? null : cr.ResponseDate,
Activity = "",
Unsubscribed = x == null ? null : cr.Unsubscribed,
Responded = x == null ? null : cr.Responded,
Clicked = x == null ? null : cr.Clicked,
Viewed = x == null ? null : cr.Viewed,
Sent = x == null ? null : cr.Sent,
Targeted = x == null ? null : cr.Targeted,
HardBounced = x == null ? null : cr.HardBounced,
SoftBounced = x == null ? null : cr.SoftBounced,
WasTargeted = x == null ? null : cr.WasTargeted,
Email = "",
Id = "",
CampaignElementId = x == null ? null : z.Id,
CampaignWaveId = "J" + (x == null ? null : x.Id),
ContactId = x == null ? null : cr.ContactId,
AtTaskId = x == null ? null : w.AtTaskId,
LinkClicked = x == null ? null : cr.Referrer,
OptTopic = x == null ? null : z.TopicId,
DiseaseState = "",
ElementDescription = x == null ? null : y.Name,
WaveDescription = x == null ? null : x.Label
};
尝试 C
var records = from cr in lstContactResponse
join jn in lstJourneyNodeData on cr.GrandparentId equals jn.Id into a
from x in a.DefaultIfEmpty()
join j in lstJourney on x.JourneyId equals j.Id into b
from y in b.DefaultIfEmpty()
join ce in lstCampaignElement on y.Name equals ce.LinkedJourney into c
from z in c.DefaultIfEmpty()
join c in lstCampaign on z.CampaignId equals c.Id into d
from w in d.DefaultIfEmpty()
select new JourneyRecord
{
CompanyName = w == null ? null : w.Company,
BrandName = w == null ? null : w.Brand,
CampaignName = w == null ? null : w.Name,
Channel = z == null ? null : z.Type,
Wave = "",
CampaignId = w == null ? null : w.Id,
ActivityDate = cr == null ? null : cr.ResponseDate,
Activity = "",
Unsubscribed = cr == null ? null : cr.Unsubscribed,
Responded = cr == null ? null : cr.Responded,
Clicked = cr == null ? null : cr.Clicked,
Viewed = cr == null ? null : cr.Viewed,
Sent = cr == null ? null : cr.Sent,
Targeted = cr == null ? null : cr.Targeted,
HardBounced = cr == null ? null : cr.HardBounced,
SoftBounced = cr == null ? null : cr.SoftBounced,
WasTargeted = cr == null ? null : cr.WasTargeted,
Email = "",
Id = "",
CampaignElementId = z == null ? null : z.Id,
CampaignWaveId = "J" + (x == null ? null : x.Id),
ContactId = cr == null ? null : cr.ContactId,
AtTaskId = w == null ? null : w.AtTaskId,
LinkClicked = cr == null ? null : cr.Referrer,
OptTopic = z == null ? null : z.TopicId,
DiseaseState = "",
ElementDescription = y == null ? null : y.Name,
WaveDescription = x == null ? null : x.Label
};
我无法通过 Linq 确定完成我想做的事情。因此,我转向了另一个方向来解决问题。
foreach (ContactResponse cr in lstContactResponse)
{
ContactResponseRecord crr = new ContactResponseRecord() {
ContactId = cr.ContactId,
ActivityDate = cr.ResponseDate,
LinkClicked = cr.Referrer};
var vJourneyNodeData = from x in lstJourneyNodeData where x.Id == cr.GrandparentId select x;
if(null != vJourneyNodeData && vJourneyNodeData.Count() > 0)
{
jnd = vJourneyNodeData.FirstOrDefault();
crr.CampaignWaveId = "J" + jnd.Id;
crr.WaveDescription = jnd.Label;
}
var vJourney = from x in lstJourney where x.Id == jnd.JourneyId select x;
if (null != vJourney && vJourney.Count() > 0)
{
j = vJourney.FirstOrDefault();
crr.OptTopic = j.TopicId;
}
var vCampaignElement = from x in lstCampaignElement where x.LinkedJourney == j.Name select x;
if (null != vCampaignElement && vCampaignElement.Count() > 0)
{
ce = vCampaignElement.FirstOrDefault();
crr.Ccg_Id = ce.CCGId;
crr.ElementDescription = ce.Description.ToString();
crr.CampaignElementId = ce.Id;
var vCampaign = from x in lstCampaign where x.Id == ce.CampaignId select x;
if (null != vCampaign && vCampaign.Count() > 0)
{
c = vCampaign.FirstOrDefault();
crr.ActivityDate = c.AtTaskId;
crr.BrandName = c.Brand;
crr.CampaignId = c.Id;
crr.CampaignName = c.Name;
crr.CompanyName = c.Company;
}
}
当然,在 LINQ 中有一种方法可以做到这一点。如果您在评论中回答了我的问题,我会为您提供确切的解决方案,现在我只举一个例子。 LINQ to Objects 与 LINQ to Entities 的技术不同,因此以下内容适用于 LINQ to Objects。
解决方案是检查左连接右侧涉及的每个 null
属性,包括 进一步的连接。值类型属性也需要转换为可为空的(这就是为什么 类 对于之前的 C#6 代码很重要)。
示例如下:
有以下"tables"
var t1 = new[]
{
new { Id = 1 , Name = "A", Date = DateTime.Today },
new { Id = 2 , Name = "B", Date = DateTime.Today},
new { Id = 3 , Name = "C", Date = DateTime.Today},
};
var t2 = new[]
{
new { Id = 1 , ParentId = 1, Name = "A1", Date = DateTime.Today },
new { Id = 2 , ParentId = 2, Name = "B1", Date = DateTime.Today },
};
var t3 = new[]
{
new { Id = 1 , ParentId = 1, Name = "A11", Date = DateTime.Today },
new { Id = 2 , ParentId = 1, Name = "A12", Date = DateTime.Today },
};
var t4 = new[]
{
new { Id = 1 , ParentId = 1, Name = "A111", Date = DateTime.Today },
};
C#6 之前版本
var query =
from e1 in t1
join e2 in t2 on e1.Id equals e2.ParentId into g2
from e2 in g2.DefaultIfEmpty()
join e3 in t3 on e2 != null ? (int?)e2.Id : null equals e3.ParentId into g3
from e3 in g3.DefaultIfEmpty()
join e4 in t4 on e3 != null ? (int?)e3.Id : null equals e4.Id into g4
from e4 in g4.DefaultIfEmpty()
select new
{
t1_Id = e1.Id,
t1_Name = e1.Name,
t1_Date = e1.Date,
t2_Id = e2 != null ? (int?)e2.Id : null,
t2_Name = e2 != null ? e2.Name : null,
t2_Date = e2 != null ? (DateTime?)e2.Date : null,
t3_Id = e3 != null ? (int?)e3.Id : null,
t3_Name = e3 != null ? e3.Name : null,
t3_Date = e3 != null ? (DateTime?)e3.Date : null,
t4_Id = e4 != null ? (int?)e4.Id : null,
t4_Name = e4 != null ? e4.Name : null,
t4_Date = e4 != null ? (DateTime?)e4.Date : null,
};
var result = query.ToList();
看起来很丑,但是很管用。
C#6 - 只需在任何右侧 属性 访问器之前添加 ?
即可获得相同的结果(重复 - 包括个加入条件)
var query =
from e1 in t1
join e2 in t2 on e1.Id equals e2.ParentId into g2
from e2 in g2.DefaultIfEmpty()
join e3 in t3 on e2?.Id equals e3.ParentId into g3
from e3 in g3.DefaultIfEmpty()
join e4 in t4 on e3?.Id equals e4.Id into g4
from e4 in g4.DefaultIfEmpty()
select new
{
t1_Id = e1.Id,
t1_Name = e1.Name,
t1_Date = e1.Date,
t2_Id = e2?.Id,
t2_Name = e2?.Name,
t2_Date = e2?.Date,
t3_Id = e3?.Id,
t3_Name = e3?.Name,
t3_Date = e3?.Date,
t4_Id = e4?.Id,
t4_Name = e4?.Name,
t4_Date = e4?.Date,
};
var result = query.ToList();