如何在 Linq 查询语法(或流利的)中进行双左外连接

How to do a double left outer join in Linq query syntax(or fluent)

var Claim   = new[] {   new { ClaimId = 10, Desc = "item 10" },
    new { ClaimId = 11, Desc = "item 11" },
    new { ClaimId = 12, Desc = "item 12" },
    new { ClaimId = 13, Desc = "item 13" }};
var Insured = new[] {   new { ClaimId = 10, IsPolicyHolder = true, IsInsured = true, Forename = "10A Pol TRUE Ins TRUE NoSiblings" },
    new { ClaimId = 11, IsPolicyHolder = true, IsInsured = false, Forename = "11A Pol TRUE Ins false NoSiblings" },
    new { ClaimId = 12, IsPolicyHolder = false, IsInsured = true, Forename = "12A Pol false Ins TRUE NoSiblings" },
    new { ClaimId = 13, IsPolicyHolder = true, IsInsured = false, Forename = "13A Pol TRUE Ins false has sibling" },
    new { ClaimId = 13, IsPolicyHolder = false, IsInsured = true, Forename = "13B Pol false Ins TRUE has sibling" }};

    Insured.Dump("Insured Table");

var leftJoinTry =
    from in1 in Insured where in1.IsPolicyHolder == true
    join p in Insured on in1.ClaimId equals p.ClaimId into ps 
    //where ps.IsInsured == true   ****ERROR****
    from p in ps.DefaultIfEmpty()
    select new { in1.ClaimId, in1.IsPolicyHolder, in1.IsInsured, in1.Forename, p_Forename = p.Forename};
leftJoinTry.Dump("leftJoinTry");    

var initialResults = from c in Claim
join pa in Insured on c.ClaimId equals pa.ClaimId where pa.IsPolicyHolder == true
join pb in Insured on pa.ClaimId equals pb.ClaimId where pb.IsInsured == true
select new { c.ClaimId, pa_Forename = pa.Forename, pb_Forename = pb.Forename, };

initialResults.Dump("initialResults");

var query =
    from in1 in Insured where in1.IsPolicyHolder == true
    join p in Insured on in1.ClaimId equals p.ClaimId into ps 
    //where ps.IsInsured == true
    from p in ps.DefaultIfEmpty()
    select new { Category = in1, ProductName = p /*== null ? "(No products)" : p.Forename*/ };
query.Dump("query");

以上在Linq pad中给出的结果集如下

请注意,所使用的数据库具有 ClaimId(int) 和 IsPolicyHolder(bool) 的主键,并且存在 IsPolicyHolder 或 IsInsured 字段必须为 True 的约束。

我真正想要的是所有IsPolicyHolder和IsInsured为True的记录,其中有一个IsPolicyHolder为True和IsInsured为False并且相同的ClaimId与IsPolicyHolder为False和IsInsured为True的记录合并如下面的 ClaimId 13。请注意,任何没有其他 ClaimId 兄弟姐妹的记录,其 IsPolicyHolder 和 IsInsured 之一设置为 False,另一个设置为 True 也必须包括在内,并将未知的 Forename(下面的斜体)设置为已知的 Forename(下面的粗体)。

var firstDate = new DateTime(2016,1,1);
var secondDate = new DateTime(2016,9,1);
var company = "Some_Co.";
var resultCombined = from c in Claims
join cc in ClaimCovers
on c.ClaimId equals cc.ClaimId
join cov in Covers
on cc.CoverId equals cov.CoverId
join pa in Insureds.Where(x => x.IsPolicyHolder == true) on c.ClaimId equals pa.ClaimId 
       into pas from pa in pas.DefaultIfEmpty() 
join pb in Insureds.Where(x => x.IsInsured == true) on c.ClaimId equals pb.ClaimId
       into pbs from pb in pbs.DefaultIfEmpty()
       join ci in ClaimIncidents
                              on c.ClaimId equals ci.ClaimId
                              where c.DateReported >= firstDate && c.DateReported <= secondDate
                                 where c.CompanyID == company
select new { c.ClaimId, PolicyRefernce = c.PolicyReference ?? "",
                                  c.ClaimReference,
                                  c.DateOfLoss,
                                  c.DateReported,
                                  cov.CoverCode,
                                  cov.Description, c.Status,
                                  ci.NotifiedBy,
                                  ci.HowNotified,
                                  ci.ClaimTypeCode,
                                  ci.CauseCode,
                                  ci.AtFault, 
                                  //pa is the first list where policyHolder = true
                                  PolicyHolderName = pa.Forename + " " + pa.Surname, pa_Postcode = pa.Postcode, 
                                  //pb is the second list where insured = true
                                  InsuredName = pb.Forename + " " + pb.Surname, pb_Postcode = pb.Postcode,};    

resultCombined.Dump();

不匹配的记录给出可以设置为空字符串等的空值...