LINQの左外部結合


539

join-on-equals-into句を使用せずにC#LINQでオブジェクトに左外部結合を実行する方法 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; }

2
あなたが達成しようとしていることの例を挙げられますか?
jeroenh

通常の左外部結合は次のようなものです。var a = from b in bb join c in cc on b.bbbbbはc.cccccからdd in dd in dd.DefaultIfEmpty()select b.sss; 私の質問は、次のようなjoin-on-equals-into句を使用してそれを行う方法はありますかvar a = from b in bb from c from cc where b.bbb == c.cccc ...など。
玩具

1
確かにありますが、人々があなたにもっと良い答えを与えることができるように、あなたがすでに持っているあなたのコードの例を投稿するべきです
ナマケモノ

「Left 除外」JOIN 探していました(「OUTER」の概念と混同しました)。この答えは私が欲しかったものに近かった。
レッドピー

回答:


598

に述べたように:

101 LINQサンプル-左外部結合

var q =
    from c in categories
    join p in products on c.Category equals p.Category into ps
    from p in ps.DefaultIfEmpty()
    select new { Category = c, ProductName = p == null ? "(No products)" : p.ProductName };

7
私は同じことを試みていますが、「結合句の式の1つの型が正しくありません」という結合演算子でエラーが発生します。
Badhon Jain 14年

3
@jain型が異なる場合、結合は機能しません。したがって、キーのデータ型が異なる可能性があります。たとえば、両方のキーはintですか?
Yooakim 14

2
解決策は何ですか?私も同じエラーに直面しており、タイプも私の場合と同じです。
Sandeep 2014年

1
@Sandeepは、参加したキーを確認します。それらが文字列型とint型である場合、文字列キーを単にintに変換するとします。
Ankit

2
更新されたリンク:101 LINQサンプル-左外部結合
BukeMan

546

データベース駆動型のLINQプロバイダーを使用する場合、非常に読みやすい左外部結合を次のように記述できます。

from maintable in Repo.T_Whatever 
from xxx in Repo.T_ANY_TABLE.Where(join condition).DefaultIfEmpty()

省略したDefaultIfEmpty()場合は、内部結合になります。

受け入れられた答えを取る:

  from c in categories
    join p in products on c equals p.Category into ps
    from p in ps.DefaultIfEmpty()

この構文は非常に紛らわしく、MULTIPLEテーブルを左結合する場合の構文は明確ではありません。

注:行ごとに導入しない限り、(適切な)データベースオプティマイザーが左結合に完全に変換できる、outer-apply / left-join-lateralと同じである
ことに注意してください。from alias in Repo.whatever.Where(condition).DefaultIfEmpty()-values(別名、実際の外部適用)。Linq-2-Objectsではこれを行わないでください(Linq-to-Objectsを使用する場合はDBオプティマイザーがないため)。

詳細な例

var query2 = (
    from users in Repo.T_User
    from mappings in Repo.T_User_Group
         .Where(mapping => mapping.USRGRP_USR == users.USR_ID)
         .DefaultIfEmpty() // <== makes join left join
    from groups in Repo.T_Group
         .Where(gruppe => gruppe.GRP_ID == mappings.USRGRP_GRP)
         .DefaultIfEmpty() // <== makes join left join

    // where users.USR_Name.Contains(keyword)
    // || mappings.USRGRP_USR.Equals(666)  
    // || mappings.USRGRP_USR == 666 
    // || groups.Name.Contains(keyword)

    select new
    {
         UserId = users.USR_ID
        ,UserName = users.USR_User
        ,UserGroupId = groups.ID
        ,GroupName = groups.Name
    }

);


var xy = (query2).ToList();

LINQ 2 SQLと共に使用すると、次の非常に読みやすいSQLクエリにうまく変換されます。

SELECT 
     users.USR_ID AS UserId 
    ,users.USR_User AS UserName 
    ,groups.ID AS UserGroupId 
    ,groups.Name AS GroupName 
FROM T_User AS users

LEFT JOIN T_User_Group AS mappings
   ON mappings.USRGRP_USR = users.USR_ID

LEFT JOIN T_Group AS groups
    ON groups.GRP_ID == mappings.USRGRP_GRP

編集:

より複雑な例については、「SQL ServerクエリをLinqクエリに変換する」も参照してください 。

また、(Linq-2-SQLの代わりに)Linq-2-Objectsで行う場合は、昔ながらの方法で行う必要があります(LINQ to SQLはこれを結合操作に正しく変換しますが、オブジェクトではこのメソッドを使用するためフルスキャンを強制し、インデックス検索を利用しません。

    var query2 = (
    from users in Repo.T_Benutzer
    join mappings in Repo.T_Benutzer_Benutzergruppen on mappings.BEBG_BE equals users.BE_ID into tmpMapp
    join groups in Repo.T_Benutzergruppen on groups.ID equals mappings.BEBG_BG into tmpGroups
    from mappings in tmpMapp.DefaultIfEmpty()
    from groups in tmpGroups.DefaultIfEmpty()
    select new
    {
         UserId = users.BE_ID
        ,UserName = users.BE_User
        ,UserGroupId = mappings.BEBG_BG
        ,GroupName = groups.Name
    }

);

21
この答えは実際に役立ちます。実際に理解できる構文を提供していただきありがとうございます。
Chris Marisic 2014年

3
WTB、NHibernate互換のLINQクエリ... :)
mxmissile

30
LINQ to SQLは、これを結合操作に正しく変換します。ただし、オブジェクトでは、このメソッドは強制的にフルスキャンを実行します。これが、公式ドキュメントに、インデックス検索のハッシュを利用できるグループ結合ソリューションが提供されている理由です。
Tamir Daniely、2015年

3
明示的な構文はjoinwhere後続の構文よりもはるかに読みやすく、明確だと思いますDefaultIfEmpty
FindOut_Quran

1
@ user3441905:テーブルaとテーブルbを結合する必要がある限り、これは可能です。しかし、それ以上になるとすぐにはなりません。しかし、テーブルが2つしかない場合でも、言い過ぎです。一番上の回答がすでに90以上の賛成票を持っていたとき、この回答は0から始まったため、人気のある意見もあなたに反対しているようです。
Stefan Steiger 2015

132

ラムダ式の使用

db.Categories    
  .GroupJoin(db.Products,
      Category => Category.CategoryId,
      Product => Product.CategoryId,
      (x, y) => new { Category = x, Products = y })
  .SelectMany(
      xy => xy.Products.DefaultIfEmpty(),
      (x, y) => new { Category = x.Category, Product = y })
  .Select(s => new
  {
      CategoryName = s.Category.Name,     
      ProductName = s.Product.Name   
  });

8
JoinとGroupJoinはどちらも、左結合を実際にはサポートしていません。GroupJoinを使用する際の秘訣は、空のグループを作成し、それらの空のグループを空の値に変換できることです。DefaultIfEmptyは単にこれを実行します。つまり、Enumerable.Empty<Product>.DefaultIfEmpty()単一の値を持つIEnumerableを返しますdefault(Product)
Tamir Daniely、2015年

61
左結合を実行するためにこれすべて??
FindOut_Quran 2015

7
これをありがとう!ラムダ式の例はそれほど多くありませんが、これは私にとってはうまくいきました。
ヨハンヘンケンズ2016年

1
答えてくれてありがとう。それは私が長年にわたって書いた生のSQL LEFT OUTER JOINに最も近いものを生み出しました
John Gathogo

1
最後のSelect()は本当に必要ありません。SelectMany()のanon objは、同じ出力用にリファクタリングできます。もう1つの考えは、より近いLEFT JOIN等価をシミュレートするために、nullについてyをテストすることです。
デニージェイコブ

46

拡張メソッドとして:

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));
    }
}

通常の結合と同じように使用します。

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

これにより時間を節約できることを願っています。


44

この例を見てください。このクエリは機能するはずです。

var leftFinal = from left in lefts
                join right in rights on left equals right.Left into leftRights
                from leftRight in leftRights.DefaultIfEmpty()
                select new { LeftId = left.Id, RightId = left.Key==leftRight.Key ? leftRight.Id : 0 };

3
rjoin intoを使用した後、select句でアクセスできますか?
Farhad Alizadeh Noori 14年

@FarhadAlizadehNooriはいできます。
Po-ta-toe

著者はおそらくr第2 from節で再利用するつもりでした。つまり、from r in lrs.DefaultIfEmpty()そうでなければ、このクエリはあまり意味がなくr、selectのコンテキストから外れているため、おそらくコンパイルすらできません。
Saeb Amini、2018

@Devart、あなたのクエリを読んだとき、それClockwiseはジョン・クリースの映画を思い出しました、笑。
Matas Vaitkevicius

1
leftRightsで左の権利にleftrightsに右に左から...ああうわあ... LEFT OUTERを使用する構文は、LINQに参加本当に明確ではないが、これらの名前は、本当にそれがさらに不明瞭にします。
Mike Gledhill、

19

拡張メソッドによる左外部結合の実装は次のようになります。

public static IEnumerable<Result> LeftJoin<TOuter, TInner, TKey, Result>(
  this IEnumerable<TOuter> outer, IEnumerable<TInner> inner
  , Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector
  , Func<TOuter, TInner, Result> resultSelector, IEqualityComparer<TKey> comparer)
  {
    if (outer == null)
      throw new ArgumentException("outer");

    if (inner == null)
      throw new ArgumentException("inner");

    if (outerKeySelector == null)
      throw new ArgumentException("outerKeySelector");

    if (innerKeySelector == null)
      throw new ArgumentException("innerKeySelector");

    if (resultSelector == null)
      throw new ArgumentException("resultSelector");

    return LeftJoinImpl(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer ?? EqualityComparer<TKey>.Default);
  }

  static IEnumerable<Result> LeftJoinImpl<TOuter, TInner, TKey, Result>(
      IEnumerable<TOuter> outer, IEnumerable<TInner> inner
      , Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector
      , Func<TOuter, TInner, Result> resultSelector, IEqualityComparer<TKey> comparer)
  {
    var innerLookup = inner.ToLookup(innerKeySelector, comparer);

    foreach (var outerElment in outer)
    {
      var outerKey = outerKeySelector(outerElment);
      var innerElements = innerLookup[outerKey];

      if (innerElements.Any())
        foreach (var innerElement in innerElements)
          yield return resultSelector(outerElment, innerElement);
      else
        yield return resultSelector(outerElment, default(TInner));
     }
   }

次に、resultselectorはnull要素を処理する必要があります。Fx。

   static void Main(string[] args)
   {
     var inner = new[] { Tuple.Create(1, "1"), Tuple.Create(2, "2"), Tuple.Create(3, "3") };
     var outer = new[] { Tuple.Create(1, "11"), Tuple.Create(2, "22") };

     var res = outer.LeftJoin(inner, item => item.Item1, item => item.Item1, (it1, it2) =>
     new { Key = it1.Item1, V1 = it1.Item2, V2 = it2 != null ? it2.Item2 : default(string) });

     foreach (var item in res)
       Console.WriteLine(string.Format("{0}, {1}, {2}", item.Key, item.V1, item.V2));
   }

4
ただし、これはオブジェクトに対するLINQのオプションにすぎず、クエリを任意のクエリプロバイダーに変換できません。これは、この操作の最も一般的な使用例です。
サービー2014

13
しかし、問題は「C#LINQでオブジェクトに左外部結合を実行する方法...」
Bertrand

12

この例を見てください

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:

今、あなたはinclude elements from the leftその要素has no matches in the rightであっても、私たちの場合、Arlene彼が右に一致していなくても取得できます

こちらが参考

方法:左外部結合を実行する(C#プログラミングガイド)


出力は次のようになります
。Arlene

10

これは一般的な形式です(他の回答ですでに提供されています)。

var c =
    from a in alpha
    join b in beta on b.field1 equals a.field1 into b_temp
    from b_value in b_temp.DefaultIfEmpty()
    select new { Alpha = a, Beta = b_value };

しかし、これは私がこれが実際に何を意味するのかを明確にしたいと思っている説明です!

join b in beta on b.field1 equals a.field1 into b_temp

基本的に、右側のエントリ(「b」のエントリ)のnull「行」を効果的に含む個別の結果セットb_tempを作成します。

次に、次の行:

from b_value in b_temp.DefaultIfEmpty()

..その結果セットを反復し、右側の「行」にデフォルトのnull値を設定し、右側の行結合の結果を「b_value」の値に結合します(つまり、右側の値)一致するレコードがある場合は手側、ない場合は「null」)。

これで、右側が別のLINQクエリの結果である場合、匿名型で構成されます。匿名型は、「何か」または「null」のいずれかになります。ただし、列挙可能な場合(リスト-MyObjectBが2つのフィールドを持つクラスなど)、そのプロパティに使用されるデフォルトの「null」値を特定することができます。

var c =
    from a in alpha
    join b in beta on b.field1 equals a.field1 into b_temp
    from b_value in b_temp.DefaultIfEmpty( new MyObjectB { Field1 = String.Empty, Field2 = (DateTime?) null })
    select new { Alpha = a, Beta_field1 = b_value.Field1, Beta_field2 = b_value.Field2 };

これにより、「b」自体がnullではないことが保証されます(ただし、指定したデフォルトのnull値を使用してそのプロパティをnullにすることができます)。これにより、b_valueのnull参照例外を取得せずにb_valueのプロパティを確認できます。null可能なDateTimeの場合、(DefaultTimeEmpty)の仕様でnullの「Type」として(DateTime?)のタイプ、つまり「nullable DateTime」を指定する必要があることに注意してください(これは、「ネイティブ」でないタイプにも適用されます。 'null可能(例:double、float)。

上記の構文をチェーンするだけで、複数の左外部結合を実行できます。


1
b_valueはどこから来たのですか?
ジャックフレイザー

9

3つ以上のテーブルを結合する必要がある場合の例を次に示します。

from d in context.dc_tpatient_bookingd
join bookingm in context.dc_tpatient_bookingm 
     on d.bookingid equals bookingm.bookingid into bookingmGroup
from m in bookingmGroup.DefaultIfEmpty()
join patient in dc_tpatient
     on m.prid equals patient.prid into patientGroup
from p in patientGroup.DefaultIfEmpty()

参照:https : //stackoverflow.com/a/17142392/2343


4

結合構文による左結合のように機能する拡張メソッド

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)}

4

以下は、メソッド構文を使用した非常に理解しやすいバージョンです。

IEnumerable<JoinPair> outerLeft =
    lefts.SelectMany(l => 
        rights.Where(r => l.Key == r.Key)
              .DefaultIfEmpty(new Item())
              .Select(r => new JoinPair { LeftId = l.Id, RightId = r.Id }));

3

person、schools、persons_schoolsの3つのテーブルがあります。persons_schoolsは、学習する学校に人を接続します。id= 6の人への参照は、persons_schoolsテーブルにはありません。ただし、id = 6の人は結果の左結合グリッドに表示されます。

List<Person> persons = new List<Person>
{
    new Person { id = 1, name = "Alex", phone = "4235234" },
    new Person { id = 2, name = "Bob", phone = "0014352" },
    new Person { id = 3, name = "Sam", phone = "1345" },
    new Person { id = 4, name = "Den", phone = "3453452" },
    new Person { id = 5, name = "Alen", phone = "0353012" },
    new Person { id = 6, name = "Simon", phone = "0353012" }
};

List<School> schools = new List<School>
{
    new School { id = 1, name = "Saint. John's school"},
    new School { id = 2, name = "Public School 200"},
    new School { id = 3, name = "Public School 203"}
};

List<PersonSchool> persons_schools = new List<PersonSchool>
{
    new PersonSchool{id_person = 1, id_school = 1},
    new PersonSchool{id_person = 2, id_school = 2},
    new PersonSchool{id_person = 3, id_school = 3},
    new PersonSchool{id_person = 4, id_school = 1},
    new PersonSchool{id_person = 5, id_school = 2}
    //a relation to the person with id=6 is absent
};

var query = from person in persons
            join person_school in persons_schools on person.id equals person_school.id_person
            into persons_schools_joined
            from person_school_joined in persons_schools_joined.DefaultIfEmpty()
            from school in schools.Where(var_school => person_school_joined == null ? false : var_school.id == person_school_joined.id_school).DefaultIfEmpty()
            select new { Person = person.name, School = school == null ? String.Empty : school.name };

foreach (var elem in query)
{
    System.Console.WriteLine("{0},{1}", elem.Person, elem.School);
}

これはおそらく質問の答えですが、あなたの答えについていくつかの説明を提供してください:)
アミール

2

これは、内部および左外部結合のLINQ構文と比較したSQL構文です。左外部結合:

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

「次の例では、製品とカテゴリをグループ結合しています。これは基本的に左結合です。into式は、カテゴリテーブルが空の場合でもデータを返します。カテゴリテーブルのプロパティにアクセスするには、列挙可能な結果から選択する必要がありますfrom clをcatList.DefaultIfEmpty()ステートメントに追加します。


1

linqで左外部結合を実行するC#//左外部結合を実行する

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/


1

MoreLinq拡張を取得した場合、同種と異種の両方の左結合がサポートされるようになりました。

http://morelinq.github.io/2.8/ref/api/html/Overload_MoreLinq_MoreEnumerable_LeftJoin.htm

例:

//Pretend a ClientCompany object and an Employee object both have a ClientCompanyID key on them

return DataContext.ClientCompany
    .LeftJoin(DataContext.Employees,                         //Table being joined
        company => company.ClientCompanyID,                  //First key
        employee => employee.ClientCompanyID,                //Second Key
        company => new {company, employee = (Employee)null}, //Result selector when there isn't a match
        (company, employee) => new { company, employee });   //Result selector when there is a match

編集:

振り返ってみるとこれはうまくいくかもしれませんが、morelinqはクエリをSQLに変換しないため、IQueryableをIEnumerableに変換します。

ここで説明されているように、代わりにGroupJoinを使用できます。https://stackoverflow.com/a/24273804/4251433

これにより、後でさらに論理操作を行う必要がある場合に備えて、IQueryableとしてとどまることが保証されます。


1

簡単な方法は、Letキーワードを使用することです。これでうまくいきます。

from AItem in Db.A
Let BItem = Db.B.Where(x => x.id == AItem.id ).FirstOrDefault() 
Where SomeCondition
Select new YourViewModel
{
    X1 = AItem.a,
    X2 = AItem.b,
    X3 = BItem.c
}

これは、左結合のシミュレーションです。Bテーブルの各アイテムがAアイテムと一致しない場合、BItemはnullを返します


0

何かを結合してフィルタリングする必要がある場合は、結合の外で行うことができます。コレクションの作成後にフィルターを実行できます。

この場合、結合条件でこれを行うと、返される行を減らします。

三項条件が使用されます (= n == null ? "__" : n.MonDayNote,)

  • オブジェクトがnull一致する(一致しない)場合は、の後ろにあるものを返し?ます。__、 この場合。

  • そうでなければ、後は何か返し:n.MonDayNote

私が自分の問題から始めた他の貢献者に感謝します。


        var schedLocations = (from f in db.RAMS_REVENUE_LOCATIONS
              join n in db.RAMS_LOCATION_PLANNED_MANNING on f.revenueCenterID equals

                  n.revenueCenterID into lm

              from n in lm.DefaultIfEmpty()

              join r in db.RAMS_LOCATION_SCHED_NOTE on f.revenueCenterID equals r.revenueCenterID
              into locnotes

              from r in locnotes.DefaultIfEmpty()
              where f.LocID == nLocID && f.In_Use == true && f.revenueCenterID > 1000

              orderby f.Areano ascending, f.Locname ascending
              select new
              {
                  Facname = f.Locname,
                  f.Areano,
                  f.revenueCenterID,
                  f.Locabbrev,

                  //  MonNote = n == null ? "__" : n.MonDayNote,
                  MonNote = n == null ? "__" : n.MonDayNote,
                  TueNote = n == null ? "__" : n.TueDayNote,
                  WedNote = n == null ? "__" : n.WedDayNote,
                  ThuNote = n == null ? "__" : n.ThuDayNote,

                  FriNote = n == null ? "__" : n.FriDayNote,
                  SatNote = n == null ? "__" : n.SatDayNote,
                  SunNote = n == null ? "__" : n.SunDayNote,
                  MonEmpNbr = n == null ? 0 : n.MonEmpNbr,
                  TueEmpNbr = n == null ? 0 : n.TueEmpNbr,
                  WedEmpNbr = n == null ? 0 : n.WedEmpNbr,
                  ThuEmpNbr = n == null ? 0 : n.ThuEmpNbr,
                  FriEmpNbr = n == null ? 0 : n.FriEmpNbr,
                  SatEmpNbr = n == null ? 0 : n.SatEmpNbr,
                  SunEmpNbr = n == null ? 0 : n.SunEmpNbr,
                  SchedMondayDate = n == null ? dMon : n.MondaySchedDate,
                  LocNotes = r == null ? "Notes: N/A" : r.LocationNote

              }).ToList();
                Func<int, string> LambdaManning = (x) => { return x == 0 ? "" : "Manning:" + x.ToString(); };
        DataTable dt_ScheduleMaster = PsuedoSchedule.Tables["ScheduleMasterWithNotes"];
        var schedLocations2 = schedLocations.Where(x => x.SchedMondayDate == dMon);

0
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; }
}

出力


0

同様の質問に対する私の回答に従って、ここに:

LinqからSQLへの左外部結合、Lambda構文を使用して2列で結合(複合結合キー)

ここコードを入手するか、私のgithubリポジトリを複製しプレイしてください!

クエリ:

        var petOwners =
            from person in People
            join pet in Pets
            on new
            {
                person.Id,
                person.Age,
            }
            equals new
            {
                pet.Id,
                Age = pet.Age * 2, // owner is twice age of pet
            }
            into pets
            from pet in pets.DefaultIfEmpty()
            select new PetOwner
            {
                Person = person,
                Pet = pet,
            };

ラムダ:

        var petOwners = People.GroupJoin(
            Pets,
            person => new { person.Id, person.Age },
            pet => new { pet.Id, Age = pet.Age * 2 },
            (person, pet) => new
            {
                Person = person,
                Pets = pet,
            }).SelectMany(
            pet => pet.Pets.DefaultIfEmpty(),
            (people, pet) => new
            {
                people.Person,
                Pet = pet,
            });

0

概要:このコードスニペットでは、Table1とTable2が1対多の関係にあるIDでグループ化する方法を示します。Id、Field1、Field2でグループ化します。サブクエリは、3番目のテーブル検索が必要で、左結合関係が必要な場合に役立ちます。左結合グループとサブクエリlinqを示します。結果は同等です。

class MyView
{
public integer Id {get,set};
    public String Field1  {get;set;}
public String Field2 {get;set;}
    public String SubQueryName {get;set;}                           
}

IList<MyView> list = await (from ci in _dbContext.Table1
                                               join cii in _dbContext.Table2
                                                   on ci.Id equals cii.Id

                                               where ci.Field1 == criterion
                                               group new
                                               {
                                                   ci.Id
                                               } by new { ci.Id, cii.Field1, ci.Field2}

                                           into pg
                                               select new MyView
                                               {
                                                   Id = pg.Key.Id,
                                                   Field1 = pg.Key.Field1,
                                                   Field2 = pg.Key.Field2,
                                                   SubQueryName=
                                                   (from chv in _dbContext.Table3 where chv.Id==pg.Key.Id select chv.Field1).FirstOrDefault()
                                               }).ToListAsync<MyView>();


 Compared to using a Left Join and Group new

IList<MyView> list = await (from ci in _dbContext.Table1
                                               join cii in _dbContext.Table2
                                                   on ci.Id equals cii.Id

                       join chv in _dbContext.Table3
                                                  on cii.Id equals chv.Id into lf_chv
                                                from chv in lf_chv.DefaultIfEmpty()

                                               where ci.Field1 == criterion
                                               group new
                                               {
                                                   ci.Id
                                               } by new { ci.Id, cii.Field1, ci.Field2, chv.FieldValue}

                                           into pg
                                               select new MyView
                                               {
                                                   Id = pg.Key.Id,
                                                   Field1 = pg.Key.Field1,
                                                   Field2 = pg.Key.Field2,
                                                   SubQueryName=pg.Key.FieldValue
                                               }).ToListAsync<MyView>();

-1
(from a in db.Assignments
     join b in db.Deliveryboys on a.AssignTo equals b.EmployeeId  

     //from d in eGroup.DefaultIfEmpty()
     join  c in  db.Deliveryboys on a.DeliverTo equals c.EmployeeId into eGroup2
     from e in eGroup2.DefaultIfEmpty()
     where (a.Collected == false)
     select new
     {
         OrderId = a.OrderId,
         DeliveryBoyID = a.AssignTo,
         AssignedBoyName = b.Name,
         Assigndate = a.Assigndate,
         Collected = a.Collected,
         CollectedDate = a.CollectedDate,
         CollectionBagNo = a.CollectionBagNo,
         DeliverTo = e == null ? "Null" : e.Name,
         DeliverDate = a.DeliverDate,
         DeliverBagNo = a.DeliverBagNo,
         Delivered = a.Delivered

     });

-1

LEFT OUTER JOINのシンプルなソリューション:

var setA = context.SetA;
var setB = context.SetB.Select(st=>st.Id).Distinct().ToList();
var leftOuter  = setA.Where(stA=> !setB.Contains(stA.Id)); 

  • 変換することができ、性能SETBを向上させるために辞書(つまりは、その後行われている場合は、この変更する必要があります!のsetB.Containsを(stA.Id) )またはHashSetの
  • 関連するフィールドが複数ある場合、これはSetオペレーションと実装するクラスIEqualityComparerを使用して実現できます。

左外部結合は、一致setAsetB返答を返します。
NetMage
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.