左外连接如何工作?我知道如何执行左外连接,SO有帮助的文章,甚至官方MSDN网站有一个光滑的例子,我将在这里用来解释我的问题 .

我的问题简而言之

from 子句可以在同一查询中多次使用,该查询将被视为子查询(源:from clause (C# Reference)) . 如果第二个 from 子句未在第一个 from 子句的range元素的子元素上使用,则它将执行交叉连接(源:from clause (C# Reference)) . 但是,我们在下面的左连接示例中看到 gj.DefaultIfEmpty() 上的第二个 from 子句没有给出相同的结果,那是怎么回事? linq查询是否执行某种关联?

来自MSDN的示例

来源How to: Perform Left Outer Joins (C# Programming Guide)

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:

来自MSDN的from子句的说明

来源from clause (C# Reference)

class CompoundFrom2
{
    static void Main()
    {
        char[] upperCase = { 'A', 'B', 'C' };
        char[] lowerCase = { 'x', 'y', 'z' };

        // The type of joinQuery1 is IEnumerable<'a>, where 'a 
        // indicates an anonymous type. This anonymous type has two 
        // members, upper and lower, both of type char. 
        var joinQuery1 =
            from upper in upperCase
            from lower in lowerCase
            select new { upper, lower };

        // The type of joinQuery2 is IEnumerable<'a>, where 'a 
        // indicates an anonymous type. This anonymous type has two 
        // members, upper and lower, both of type char. 
        var joinQuery2 =
            from lower in lowerCase
            where lower != 'x'
            from upper in upperCase
            select new { lower, upper };


        // Execute the queries.
        Console.WriteLine("Cross join:");
        // Rest the mouse pointer on joinQuery1 to verify its type. 
        foreach (var pair in joinQuery1)
        {
            Console.WriteLine("{0} is matched to {1}", pair.upper, pair.lower);
        }

        Console.WriteLine("Filtered non-equijoin:");
        // Rest the mouse pointer over joinQuery2 to verify its type. 
        foreach (var pair in joinQuery2)
        {
            Console.WriteLine("{0} is matched to {1}", pair.lower, pair.upper);
        }

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
        Cross join:
        A is matched to x
        A is matched to y
        A is matched to z
        B is matched to x
        B is matched to y
        B is matched to z
        C is matched to x
        C is matched to y
        C is matched to z
        Filtered non-equijoin:
        y is matched to A
        y is matched to B
        y is matched to C
        z is matched to A
        z is matched to B
        z is matched to C
        */

到目前为止我有什么

我猜Linq引擎做的是这样的

  • 执行连接操作

  • 由第一个加入成员分组
    对于上一步不是空结果的每个第一个连接成员

  • ,将组合元素作为子元素追加

我当然没有任何关于这个想法的参考,但这是有道理的,甚至可以解释为什么必须使用 DefaultIfEmpty () .