Linq离开加入了可空的领域

hun*_*ude 3 c# linq

在下面的示例中,我有entity1,其中user_id是可以为null的int,有时它确实为null.Entity2类似于通过user_id将entity1连接到entity3的桥梁,以获取person_id并最终获得相应的fullname.

我的目标是编写一个linq查询,其中如果entity1的user_id为null,则不抛出NullReferenceException,但为fullname属性获取null.

鉴于以下实体,我希望我的查询返回:

  • codeOfEntity ="21006.040",fullname = null
  • codeOfEntity ="14006.010",fullname ="John Smith"
  • codeOfEntity ="21006.020",fullname = null
  • codeOfEntity ="35716.001",fullname ="Dave Doe"
  • codeOfEntity ="11153.013",fullname ="Zach White"

实体:

class entity1
{
    public int? user_id { get; set; }
    public string codeOfEntity { get; set; }
}

class entity2
{
    public int user_id { get; set; }
    public int person_id { get; set; }
}

class entity3
{
    public int person_id { get; set; }
    public string fullname { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

并填写如下:

var listOfEntity1 = new List<entity1>()
{
    new entity1() { user_id = null, codeOfEntity = "21006.040" },
    new entity1() { user_id = 10, codeOfEntity = "14006.010" },
    new entity1() { user_id = null, codeOfEntity = "21006.020" },
    new entity1() { user_id = 1, codeOfEntity = "35716.001"},
    new entity1() { user_id = 4, codeOfEntity = "11153.013" }
};

var listOfEntity2 = new List<entity2>()
{
    new entity2() { user_id = 1, person_id = 100 },
    new entity2() { user_id = 4, person_id = 400 },
    new entity2() { user_id = 10, person_id = 1000 }
};

var listOfEntity3 = new List<entity3>()
{
    new entity3() { person_id = 100, fullname = "John Smith" },
    new entity3() { person_id = 400, fullname = "Dave Doe" },
    new entity3() { person_id = 1000, fullname = "Zach White" }
};
Run Code Online (Sandbox Code Playgroud)

我的查询抛出NullReferenceException:

var result = (from e1 in listOfEntity1
              join e2 in listOfEntity2 on e1.user_id equals e2.user_id into e2Group
              from e2 in e2Group.DefaultIfEmpty()
              join e3 in listOfEntity3 on e2.person_id equals e3.person_id into e3Group
              from e3 in e3Group.DefaultIfEmpty()
              select new { e1.codeOfEntity, e3.fullname }).ToList();
Run Code Online (Sandbox Code Playgroud)

谢谢.

sat*_*esh 7

使用c#6.0的空传播

var result = (from e1 in listOfEntity1
              join e2 in listOfEntity2 on e1.user_id equals e2.user_id into e2Group
              from e2 in e2Group.DefaultIfEmpty()
              join e3 in listOfEntity3 on e2?.person_id equals e3.person_id into e3Group
              from e3 in e3Group.DefaultIfEmpty()
              select new { e1.codeOfEntity, e3?.fullname }).ToList();
Run Code Online (Sandbox Code Playgroud)

注意连接条件的简单变化和select.改变e2.person_ide2?.person_idjoine3.fullnamee3?.fullnameselect.

但是,如果你不能使用c#6.0,这里有另一种选择

var result = (from e1 in listOfEntity1
              join e2 in listOfEntity2 on e1.user_id equals e2.user_id into e2Group
              from e2 in e2Group.DefaultIfEmpty()
              join e3 in listOfEntity3 on (e2==null?-1:e2.person_id) equals e3.person_id into e3Group
              from e3 in e3Group.DefaultIfEmpty()
              select new { e1.codeOfEntity, fullname=(e3==null?null:e3.fullname) }).ToList();
Run Code Online (Sandbox Code Playgroud)

  • 请注意,由于这是一个 Linq-to-Objects 查询,因此它会起作用。但是,如果处理可查询对象,第一个根本不起作用(因为表达式中不支持空传播运算符),第二个可能会也可能不会对所有查询提供程序起作用。在 C#6 之前,首选的解决方案是提供一个默认实例作为 `DefaultIfEmpty()` 的参数。 (2认同)