it-swarm.com.de

LINQ Inner-Join vs. Left-Join

Verwenden der Erweiterungssyntax Ich versuche, einen Link mit LINQ auf zwei Listen zu erstellen, die ich habe. Das Folgende ist aus der Microsoft-Hilfe, aber ich habe es geändert, um zu zeigen, dass die Liste der Haustiere keine Elemente enthält. Was ich am Ende ende, ist eine Liste von 0 Elementen. Ich gehe davon aus, dass dies daran liegt, dass ein Inner-Join stattfindet. Am Ende möchte ich eine Liste von 3 Elementen (den 3-Personen-Objekten) mit leeren Daten für die fehlenden Elemente angeben. eine Linksverknüpfung. Ist das möglich?

Person magnus = new Person { Name = "Hedlund, Magnus" };
Person terry = new Person { Name = "Adams, Terry" };
Person charlotte = new Person { Name = "Weiss, Charlotte" };

//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 daisy = new Pet { Name = "Daisy", Owner = magnus };

List<Person> people = new List<Person> { magnus, terry, charlotte };
//List<Pet> pets = new List<Pet> { barley, boots, whiskers, daisy };
List<Pet> pets = new List<Pet>();

// Create a list of Person-Pet pairs where 
// each element is an anonymous type that contains a
// Pet's name and the name of the Person that owns the Pet.
var query =
    people.Join(pets,
                person => person,
                pet => pet.Owner,
                (person, pet) =>
                    new { OwnerName = person.Name, Pet = pet.Name }).ToList();
41
Guy

Ich denke, wenn Sie Erweiterungsmethoden verwenden möchten, müssen Sie GroupJoin verwenden.

var query =
    people.GroupJoin(pets,
                     person => person,
                     pet => pet.Owner,
                     (person, petCollection) =>
                        new { OwnerName = person.Name,
                              Pet = PetCollection.Select( p => p.Name )
                                                 .DefaultIfEmpty() }
                    ).ToList();

Möglicherweise müssen Sie mit dem Auswahlausdruck herumspielen. Ich bin nicht sicher, ob Sie dies wünschen, wenn Sie eine 1-zu-Viele-Beziehung haben.

Ich denke, es ist etwas einfacher mit der LINQ Query-Syntax

var query = (from person in context.People
             join pet in context.Pets on person equals pet.Owner
             into tempPets
             from pets in tempPets.DefaultIfEmpty()
             select new { OwnerName = person.Name, Pet = pets.Name })
            .ToList();
74
tvanfosson

Sie müssen die verbundenen Objekte in einen Satz bringen und dann DefaultIfEmpty anwenden, wie JPunyon sagte:

Person magnus = new Person { Name = "Hedlund, Magnus" };
Person terry = new Person { Name = "Adams, Terry" };
Person charlotte = new Person { Name = "Weiss, Charlotte" };

Pet barley = new Pet { Name = "Barley", Owner = terry };
List<Person> people = new List<Person> { magnus, terry, charlotte };
List<Pet> pets = new List<Pet>{barley};

var results =
    from person in people
    join pet in pets on person.Name equals pet.Owner.Name into ownedPets
    from ownedPet in ownedPets.DefaultIfEmpty(new Pet())
    orderby person.Name
    select new { OwnerName = person.Name, ownedPet.Name };


foreach (var item in results)
{
    Console.WriteLine(
        String.Format("{0,-25} has {1}", item.OwnerName, item.Name ) );
}

Ausgänge:

Adams, Terry              has Barley
Hedlund, Magnus           has
Weiss, Charlotte          has
15
Gishu

Ich habe die folgende Fehlermeldung, wenn das gleiche Problem aufgetreten ist:

Der Typ eines der Ausdrücke in der Join-Klausel ist falsch. Die Typeninferenz ist beim Aufruf von 'GroupJoin' fehlgeschlagen.  

Gelöst, als ich denselben Eigenschaftsnamen verwendete, funktionierte es.

(...)

join enderecoST in db.PessoaEnderecos on 
    new 
      {  
         CD_PESSOA          = nf.CD_PESSOA_ST, 
         CD_ENDERECO_PESSOA = nf.CD_ENDERECO_PESSOA_ST 
      } equals 
    new 
    { 
         enderecoST.CD_PESSOA, 
         enderecoST.CD_ENDERECO_PESSOA 
    } into eST

(...)

5
João Vieira

Hier ist ein guter Blogbeitrag, der gerade von Fabrice (Autor von LINQ in Action) veröffentlicht wurde. Er enthält das Material in der von mir gestellten Frage. Ich lege es hier als Referenz, da die Leser der Frage dies nützlich finden werden.

Konvertieren von LINQ-Abfragen von der Abfragesyntax in die Methoden Operatorsyntax - /

3
Guy

Linke Joins in LINQ sind mit der DefaultIfEmpty () - Methode möglich. Ich habe jedoch nicht die genaue Syntax für Ihren Fall ...

Eigentlich denke ich, wenn man Haustiere nur in pets.DefaultIfEmpty () in der Abfrage ändert, könnte es funktionieren ...

EDIT: Ich sollte wirklich nicht antworten, wenn es spät ist ...

2
Jason Punyon

Wenn Sie tatsächlich über eine Datenbank verfügen, ist dies der einfachste Weg:

var lsPetOwners = ( from person in context.People
                    from pets in context.Pets
                        .Where(mypet => mypet.Owner == person.ID) 
                        .DefaultIfEmpty()
                     select new { OwnerName = person.Name, Pet = pets.Name }
                   ).ToList();
0
Stefan Steiger