外部连接两个具有空值的表
Outer join two tables with null values
我有这个数据结构:
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}
};
现在我想得到所有人的名单和他们的宠物名字(如果没有宠物,则为空)
结果应该是
Foo - FooBoy
Bar - null
我试过了
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()
,我只会得到第一个人。
题改前
(最初 link table 引用了宠物,而不是 ID。)
在我看来你只需要一个连接,因为你可以只使用 link 中的 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
和 links
之间进行连接即可:
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 };
如果你想用 link table 同时获得人和宠物,你可以这样做:
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())(可能只适用于内存中的联接,因为您的原始联接适用于数据库)
var query = from person in people
join lnk in links on person equals lnk.Person into linkPets
from link in linkPets.DefaultIfEmpty(new Link())
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) };
我有这个数据结构:
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}
};
现在我想得到所有人的名单和他们的宠物名字(如果没有宠物,则为空) 结果应该是
Foo - FooBoy
Bar - null
我试过了
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()
,我只会得到第一个人。
题改前
(最初 link table 引用了宠物,而不是 ID。)
在我看来你只需要一个连接,因为你可以只使用 link 中的 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
和 links
之间进行连接即可:
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 };
如果你想用 link table 同时获得人和宠物,你可以这样做:
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())(可能只适用于内存中的联接,因为您的原始联接适用于数据库)
var query = from person in people
join lnk in links on person equals lnk.Person into linkPets
from link in linkPets.DefaultIfEmpty(new Link())
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) };