C# 外部使用空值连接两个表

C# 外部使用空值连接两个表,c#,linq,outer-join,C#,Linq,Outer Join,我有这样的数据结构: class Person { public string FirstName { get; set; } } class Pet { public int Id { get; set; } public string Name { get; set; } } class Link { public Person Person { get; set; } public int PetId { get; set; } } 这些数据:

我有这样的数据结构:

class Person
{
    public string FirstName { get; set; }
}

class Pet
{
    public int Id { get; set; }
    public string Name { get; set; }
}

class Link
{
    public Person Person { get; set; }
    public int PetId { get; set; }
}
这些数据:

List<Person> people = new List<Person>
{
    new Person {FirstName = "Foo"},
    new Person {FirstName = "Bar"}
};
List<Pet> pets = new List<Pet>
{
    new Pet {Id = 1, Name = "FooBoy"},
};
List<Link> links = new List<Link>
{
    new Link {Person = people.First(), PetId = pets.First().Id}
};
我试过了

var query = from person in people
    join lnk in links on person equals lnk.Person into linkPets
    from link in linkPets.DefaultIfEmpty()
    join p in pets on link.PetId equals p.Id into subPets
    from subPet in subPets.DefaultIfEmpty()
    select new { person.FirstName, PetName = (subPet == null ? String.Empty : subPet.Name) };

但是我在
link.Pet
上得到空引用异常。如果我删除
linkPets.DefaultIfEmpty()
,我只会得到第一个人。

在问题更改之前

(最初链接表引用的是pet,而不是ID。)

在我看来,您只需要一个加入,因为您可以从链接中使用
Pet
属性,其中有一个:

var query = from person in people
            join lnk in links on person equals lnk.Person into linkPets
            from link in linkPets.DefaultIfEmpty()
            select new { person.FirstName,
                         PetName = link == null ? "" : link.Pet.Name };
问题更改后

我保留了上面的原始解决方案,因为很容易将修改后的问题转换为原始问题-只需先在
pets
链接之间进行连接即可:

var fullLinks = from link in links
                join pet in pets on link.PetId equals pet.Id
                select new { link.Person, Pet = pet };

var query = from person in people
    join lnk in fullLinks on person equals lnk.Person into linkPets
    from link in linkPets.DefaultIfEmpty()
    select new { person.FirstName,
                 PetName = link == null ? "" : link.Pet.Name };
如果你愿意,你可以在一份声明中这样做,但我不会:

var query = from person in people
    join lnk in (from link in links
                 join pet in pets on link.PetId equals pet.Id
                 select new { link.Person, Pet = pet } )
      on person equals lnk.Person into linkPets
    from link in linkPets.DefaultIfEmpty()
    select new { person.FirstName,
                 PetName = link == null ? "" : link.Pet.Name };

问题更改前

(最初链接表引用的是pet,而不是ID。)

在我看来,您只需要一个加入,因为您可以从链接中使用
Pet
属性,其中有一个:

var query = from person in people
            join lnk in links on person equals lnk.Person into linkPets
            from link in linkPets.DefaultIfEmpty()
            select new { person.FirstName,
                         PetName = link == null ? "" : link.Pet.Name };
问题更改后

我保留了上面的原始解决方案,因为很容易将修改后的问题转换为原始问题-只需先在
pets
链接之间进行连接即可:

var fullLinks = from link in links
                join pet in pets on link.PetId equals pet.Id
                select new { link.Person, Pet = pet };

var query = from person in people
    join lnk in fullLinks on person equals lnk.Person into linkPets
    from link in linkPets.DefaultIfEmpty()
    select new { person.FirstName,
                 PetName = link == null ? "" : link.Pet.Name };
如果你愿意,你可以在一份声明中这样做,但我不会:

var query = from person in people
    join lnk in (from link in links
                 join pet in pets on link.PetId equals pet.Id
                 select new { link.Person, Pet = pet } )
      on person equals lnk.Person into linkPets
    from link in linkPets.DefaultIfEmpty()
    select new { person.FirstName,
                 PetName = link == null ? "" : link.Pet.Name };

如果您想通过链接表同时获得人物和宠物,可以执行以下操作:

var result= (
        from person in people
        from lnk in links
            .Where (w =>w.Person==person).DefaultIfEmpty()
        from p in pets
            .Where (w =>w==(lnk==null?null:lnk.Pet)).DefaultIfEmpty()
        select new { person.FirstName, PetName = (p == null ? String.Empty : p.Name) }
    ).Dump();

如果您想通过链接表同时获得人物和宠物,可以执行以下操作:

var result= (
        from person in people
        from lnk in links
            .Where (w =>w.Person==person).DefaultIfEmpty()
        from p in pets
            .Where (w =>w==(lnk==null?null:lnk.Pet)).DefaultIfEmpty()
        select new { person.FirstName, PetName = (p == null ? String.Empty : p.Name) }
    ).Dump();

另一种解决方案是使用linkPets.DefaultIfEmpty(new Link())(可能只适用于内存中的连接,因为您最初的连接适用于数据库)


另一种解决方案是使用linkPets.DefaultIfEmpty(new Link())(可能只适用于内存中的连接,因为您最初的连接适用于数据库)


如果有一只没有主人的宠物,你也需要吗?不,我不需要没有主人的宠物如果有一只没有主人的宠物,你也需要吗?不,我不需要没有主人的宠物。我想我把我的任务简化了,你找到了一个简单的解决办法。我更新了问题。最重要的是:我在链接中没有宠物对象。我只有一个身份证。我想我把我的任务简化了,你找到了一个简单的解决办法。我更新了问题。最重要的是:我在链接中没有宠物对象。我只有身份证。