简体   繁体   中英

Linq left join when the class on the left side of equals can be null

Consider the following case:

Classes

public class Nested
{
    public Nested(int id){ Id = id; }
    public int? Id {get; set;}  
}

public class Pair
{
    public Nested NestedType {get; set;}
    public string Name {get; set;}  
}

public class Match
{
    public int? Id {get; set;}
    public string Name {get; set;}  
}

Instances

var p1 = new Pair();
p1.NestedType = new Nested(1);
p1.Name = "a";          

var p2 = new Pair();
p2.NestedType = null;
p2.Name = "b";

var p3 = new Pair();
p3.NestedType = new Nested(3);
p3.Name = "c";

List<Pair> pairs = new List<Pair>() {p1, p2, p3};

var m1 = new Match();
m1.Id = 1;
m1.Name = "AA";

var m2 = new Match();
m2.Id = null;
m2.Name = "BB";

var m3 = new Match();
m3.Id = 3;
m3.Name = "CC";

List<Match> matches = new List<Match>(){m1, m2, m3};

Query

var query = from p in pairs
            join m in matches on p.NestedType.Id equals m.Id into pm
            from m in pm.DefaultIfEmpty()                               
            select new
            {
               PairName = p.Name,
               MatchId = m != null ? m.Id : null
               MatchName = m != null ? m.Name : null
            };

The query will throw an exception on the equals statement line when p.NestedType is null.

What I'd like to achieve is this: When p.NestedType is null, a null value should be placed instead of it; It is as if p.NestedType is assigned but its Id is null. Can it be done?

EDIT: I have to use C# 5.0.

With a where(...) clause, you can prevent the null reference exception throwing in your case and check if this produce desired result for your cases:

var query = from p in pairs
            where p.NestedType!=null //Notice the where condition added
            join m in matches on p.NestedType.Id equals m.Id into pm
            from m in pm.DefaultIfEmpty()
            select new
            {
                PairName = p.Name,
                MatchId = m != null ? m.Id : null,
                MatchName = m != null ? m.Name : null
            };

OR

If you want to get all left side values always, for example, in your case if the result should look something like following, you can use Null-Conditional Operator in C# 6.0 + :

在此处输入图片说明

var query = from p in pairs
            join m in matches on p?.NestedType?.Id equals m.Id into pm //Notice Null-Conditional operator: p?.NestedType?.Id
            from m in pm.DefaultIfEmpty()
            select new
            {
                PairName = p.Name,
                MatchId = m != null ? m.Id : null,
                MatchName = m != null ? m.Name : null
            };

OR

If we need to do it in C# 5 as commented below, you can do:

var query = from p in pairs
            let nestedTypeId = (p != null && p.NestedType != null) ? p.NestedType.Id : null
            join m in matches on nestedTypeId equals m.Id into pm
            from m in pm.DefaultIfEmpty()
            select new
            {
                PairName = p.Name,
                MatchId = m != null ? m.Id : null,
                MatchName = m != null ? m.Name : null
            };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM