如何在c# LINQ中执行左外连接到对象而不使用join-on-equal -into子句?有办法用where子句来实现吗? 正确的问题: 内连接很简单,我有一个这样的解决方案

List<JoinPair> innerFinal = (from l in lefts from r in rights where l.Key == r.Key
                             select new JoinPair { LeftId = l.Id, RightId = r.Id})

但是对于左外连接,我需要一个解决方案。我的是这样的,但它不工作

List< JoinPair> leftFinal = (from l in lefts from r in rights
                             select new JoinPair { 
                                            LeftId = l.Id, 
                                            RightId = ((l.Key==r.Key) ? r.Id : 0
                                        })

其中JoinPair是一个类:

public class JoinPair { long leftId; long rightId; }

当前回答

现在作为一个扩展方法:

public static class LinqExt
{
    public static IEnumerable<TResult> LeftOuterJoin<TLeft, TRight, TKey, TResult>(this IEnumerable<TLeft> left, IEnumerable<TRight> right, Func<TLeft, TKey> leftKey, Func<TRight, TKey> rightKey,
        Func<TLeft, TRight, TResult> result)
    {
        return left.GroupJoin(right, leftKey, rightKey, (l, r) => new { l, r })
             .SelectMany(
                 o => o.r.DefaultIfEmpty(),
                 (l, r) => new { lft= l.l, rght = r })
             .Select(o => result.Invoke(o.lft, o.rght));
    }
}

像平常使用join一样使用:

var contents = list.LeftOuterJoin(list2, 
             l => l.country, 
             r => r.name,
            (l, r) => new { count = l.Count(), l.country, l.reason, r.people })

希望这能为您节省一些时间。

其他回答

在linqc#中执行左外连接 //执行左外连接

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

class Child
{
    public string Name { get; set; }
    public Person Owner { get; set; }
}
public class JoinTest
{
    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" };

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

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

        var query = from person in people
                    join child in childs
                    on person equals child.Owner into gj
                    from subpet in gj.DefaultIfEmpty()
                    select new
                    {
                        person.FirstName,
                        ChildName = subpet!=null? subpet.Name:"No Child"
                    };
                       // PetName = subpet?.Name ?? String.Empty };

        foreach (var v in query)
        {
            Console.WriteLine($"{v.FirstName + ":",-25}{v.ChildName}");
        }
    }

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

https://dotnetwithhamid.blogspot.in/

扩展方法,类似于使用join语法的左连接

public static class LinQExtensions
{
    public static IEnumerable<TResult> LeftJoin<TOuter, TInner, TKey, TResult>(
        this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, 
        Func<TOuter, TKey> outerKeySelector, 
        Func<TInner, TKey> innerKeySelector, 
        Func<TOuter, TInner, TResult> resultSelector)
    {
        return outer.GroupJoin(
            inner, 
            outerKeySelector, 
            innerKeySelector,
            (outerElement, innerElements) => resultSelector(outerElement, innerElements.FirstOrDefault()));
    }
}

我刚刚在。net内核中编写了它,它看起来像预期的那样工作。

小测试:

        var Ids = new List<int> { 1, 2, 3, 4};
        var items = new List<Tuple<int, string>>
        {
            new Tuple<int, string>(1,"a"),
            new Tuple<int, string>(2,"b"),
            new Tuple<int, string>(4,"d"),
            new Tuple<int, string>(5,"e"),
        };

        var result = Ids.LeftJoin(
            items,
            id => id,
            item => item.Item1,
            (id, item) => item ?? new Tuple<int, string>(id, "not found"));

        result.ToList()
        Count = 4
        [0]: {(1, a)}
        [1]: {(2, b)}
        [2]: {(3, not found)}
        [3]: {(4, d)}

这是一种SQL语法,与用于内连接和左外连接的LINQ语法相比。 左外连接:

http://www.ozkary.com/2011/07/linq-to-entity-inner-and-left-joins.html

下面的示例在产品和类别之间进行组连接。这本质上是左连接。即使类别表为空,into表达式也会返回数据。要访问类别表的属性,现在必须通过在catList.DefaultIfEmpty()语句中添加from cl从可枚举结果中进行选择。

看看这个例子

class Person
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Phone { get; set; }
}

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

public static void LeftOuterJoinExample()
{
    Person magnus = new Person {ID = 1, FirstName = "Magnus", LastName = "Hedlund"};
    Person terry = new Person {ID = 2, FirstName = "Terry", LastName = "Adams"};
    Person charlotte = new Person {ID = 3, FirstName = "Charlotte", LastName = "Weiss"};
    Person arlene = new Person {ID = 4, 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
        where person.ID == 4
        join pet in pets on person equals pet.Owner  into personpets
        from petOrNull in personpets.DefaultIfEmpty()
        select new { Person=person, Pet = petOrNull}; 



    foreach (var v in query )
    {
        Console.WriteLine("{0,-15}{1}", v.Person.FirstName + ":", (v.Pet == null ? "Does not Exist" : v.Pet.Name));
    }
}

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

现在你可以从左边包含元素,即使那个元素在右边没有匹配,在我们的例子中,我们检索了Arlene,即使他在右边没有匹配

这是参考资料

如何:执行左外连接(c#编程指南)

class Program
{
    List<Employee> listOfEmp = new List<Employee>();
    List<Department> listOfDepart = new List<Department>();

    public Program()
    {
        listOfDepart = new List<Department>(){
            new Department { Id = 1, DeptName = "DEV" },
            new Department { Id = 2, DeptName = "QA" },
            new Department { Id = 3, DeptName = "BUILD" },
            new Department { Id = 4, DeptName = "SIT" }
        };


        listOfEmp = new List<Employee>(){
            new Employee { Empid = 1, Name = "Manikandan",DepartmentId=1 },
            new Employee { Empid = 2, Name = "Manoj" ,DepartmentId=1},
            new Employee { Empid = 3, Name = "Yokesh" ,DepartmentId=0},
            new Employee { Empid = 3, Name = "Purusotham",DepartmentId=0}
        };

    }
    static void Main(string[] args)
    {
        Program ob = new Program();
        ob.LeftJoin();
        Console.ReadLine();
    }

    private void LeftJoin()
    {
        listOfEmp.GroupJoin(listOfDepart.DefaultIfEmpty(), x => x.DepartmentId, y => y.Id, (x, y) => new { EmpId = x.Empid, EmpName = x.Name, Dpt = y.FirstOrDefault() != null ? y.FirstOrDefault().DeptName : null }).ToList().ForEach
            (z =>
            {
                Console.WriteLine("Empid:{0} EmpName:{1} Dept:{2}", z.EmpId, z.EmpName, z.Dpt);
            });
    }
}

class Employee
{
    public int Empid { get; set; }
    public string Name { get; set; }
    public int DepartmentId { get; set; }
}

class Department
{
    public int Id { get; set; }
    public string DeptName { get; set; }
}

输出