为什么linq join是单向的?

时间:2013-08-16 16:08:59

标签: linq

我正在http://msdn.microsoft.com/en-us/library/vstudio/bb397895.aspx

阅读左外连接
    class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    class Pet
    {
        public string Name { get; set; }
        public Person Owner { get; set; }
    }

    public static void LeftOuterJoinExample()
    {
        Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
        Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
        Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
        Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };

        Pet barley = new Pet { Name = "Barley", Owner = terry };
        Pet boots = new Pet { Name = "Boots", Owner = terry };
        Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
        Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry };
        Pet daisy = new Pet { Name = "Daisy", Owner = magnus };

        // Create two lists.
        List<Person> people = new List<Person> { magnus, terry, charlotte, arlene };
        List<Pet> pets = new List<Pet> { barley, boots, whiskers, bluemoon, daisy };

        var query = from person in people
                    join pet in pets on person equals pet.Owner into gj
                    from subpet in gj.DefaultIfEmpty()
                    select new { person.FirstName, PetName = (subpet == null ? String.Empty : subpet.Name) };

        foreach (var v in query)
        {
            Console.WriteLine("{0,-15}{1}", v.FirstName + ":", v.PetName);
        }
    }

    // This code produces the following output: 
    // 
    // Magnus:         Daisy 
    // Terry:          Barley 
    // Terry:          Boots 
    // Terry:          Blue Moon 
    // Charlotte:      Whiskers 
    // Arlene:

我想了解外连接,所以我稍微调整了一下

    Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
    Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
    Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
    Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };
    **Person Momo = new Person { FirstName = "Momo", LastName = "Shawn" };**

    **Pet kaw = new Pet { Name = "Kaw", Owner = Momo };**
    Pet barley = new Pet { Name = "Barley", Owner = terry };
    Pet boots = new Pet { Name = "Boots", Owner = terry };
    Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
    Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry };
    Pet daisy = new Pet { Name = "Daisy", Owner = magnus };

    // Create two lists.
    List<Person> people = new List<Person> { magnus, terry, charlotte, arlene };
    List<Pet> pets = new List<Pet> { barley, boots, whiskers, bluemoon, daisy, **kaw** };

    var query = from pet in pets
                join person in people on pet.Owner equals person into gj
                from subpet in gj.DefaultIfEmpty()
                select new { name = (pet.Owner == null ? "unknown": person.FirstName) , PetName = (subpet == null ? String.Empty : subpet.Name) };

    foreach (var v in query)
    {
        Console.WriteLine("{0,-15}{1}", v.name + ":", v.PetName);
    }

智能感知不会显示。为什么?我一直认为你可以在连接中交换左手侧和右手侧。但显然,你不能。

有没有文件可以解释这个?

2 个答案:

答案 0 :(得分:1)

  

智能感知不会出现在人身上。为什么?

因为它只在join ... into子句中的范围内。但是你无论如何都要选择每个person值:

from subpet in gj.DefaultIfEmpty()

...所以只需使用subpet代替person。哎呀,如果你愿意,你甚至可以调用范围变量person

var query = from pet in pets
            join person in people on pet.Owner equals person into gj
            from person in gj.DefaultIfEmpty()
            ...

为什么为什么你正在调用范围变量subpet并不清楚,因为它会是一个人。也许误解了join ... into的作用?有关详细信息,请参阅MSDN article on join,或者查看我的Edulinq blog post on query expressions

说实话,一开始并不清楚为什么这个联接有用 - 看起来宠物只能拥有一个主人,在这种情况下你真的只是检查pet.Owner是否在people。通常,当可以有多个元素时执行分组。例如,反过来更有意义:

var query = from person in people
            join pet in pets on person equals pet.Owner into gj
            from pet in gj.DefaultIfEmpty()
            ...

现在你找到每个人,并列出他们的宠物 - 或者注意他们是否没有宠物。

您要在查询开始时尝试实现什么目标?

答案 1 :(得分:1)

由于您将其加入gj,因此无法访问此人。而不是person.FirstName,请使用gj.FirstOrDefault().FirstName

可能值得改变这样的事情吗?

var query = 
    from pet in pets
    from person in people.Where(o => o == pet.Owner).DefaultIfEmpty()
    select new
    {
        name = (person == null ? "unknown" : person.FirstName),
        PetName = pet.Name
    };