2009-04-02 3 views
13

Ich habe zwei Objekte, A & B für diese Diskussion. Ich kann diese Objekte (Tabellen) über eine gemeinsame Beziehung oder einen Fremdschlüssel verbinden. Ich benutze linq um diesen Join zu machen und ich möchte nur ObjectA in meiner Ergebnismenge zurückgeben; Ich möchte jedoch eine Eigenschaft von ObejctA mit Daten von ObjectB während des Joins aktualisieren, so dass die ObjectAs, die ich aus meiner LINQ-Abfrage erhalte, sich "geringfügig" von ihrem ursprünglichen Zustand in dem Speichermedium der Wahl unterscheiden.LINQ In-Line-Eigenschaft Update während Join

Hier meine Frage ist, können Sie sehen, dass ich gerade wie objectA.SomeProperty etwas in der Lage sein tun möchte = objectB.AValueIWantBadly

Ich weiß, dass ich in meinem wählen ein neues tun könnte und neue OBjectAs spin up , aber ich möchte das möglichst vermeiden und einfach ein Feld aktualisieren.

return from objectA in GetObjectAs() 
    join objectB in GetObjectBs() 
      on objectA.Id equals objectB.AId 
      // update object A with object B data before selecting it 
    select objectA; 

Antwort

22

Update-Methode auf Ihre KlasseA hinzufügen

class ClassA { 
    public ClassA UpdateWithB(ClassB objectB) { 
    // Do the update 
    return this; 
    } 
} 

dann

return from objectA in GetObjectAs() 
    join objectB in GetObjectBs() 
      on objectA.Id equals objectB.AId 
      // update object A with object B data before selecting it 
    select objectA.UpdateWithB(objectB); 

EDIT:

Oder eine lokale Lambda-Funktion wie:

Func<ClassA, ClassB, ClassA> f = ((a,b)=> { a.DoSomethingWithB(b); return a;}); 
return from objectA in GetObjectAs() 
     join objectB in GetObjectBs() 
     on objectA.Id equals objectB.AId 
     select f(objectA , objectA); 
+0

dies funktioniert nicht für linq-to-sql, wo ich eine Eigenschaft habe, die '[NotMapped]' Attribut haben – th1rdey3

0

können Sie die Let-Anweisung versuchen? (nicht an meinem Rechner, um das selbst auszuprobieren):

return from objectA in GetObjectAs() 
join objectB in GetObjectBs() 
on objectA.Id equals objectB.AId 
let objectA.SomeProperty = objectB.AValueIWantBadly 
select objectA; 
+0

nicht versuchen können, können Sie das nicht tun; Lassen Sie nur neue Variablen erstellen - es tut keine Zuweisung. –

+0

Ich habe das versucht und der obige Kommentar ist korrekt ... nein. – JPrescottSanders

2

Aus dem Wort "Tabellen" klingt es, als ob Sie diese Daten aus einer Datenbank bekommen. In welchem ​​Fall; nein: das kannst du nicht machen. Die nächstgelegene Sie tun können, würde die Objekte und die zusätzlichen Spalten auswählen, und die Eigenschaften aktualisieren danach:

var qry = from objectA in GetObjectAs() 
      join objectB in GetObjectBs() 
      on objectA.Id equals objectB.AId 
      select new { A = objectA, 
       objectB.SomeProp, objectB.SomeOtherProp }; 

foreach(var item in qry) { 
    item.A.SomeProp = item.SomeProp; 
    item.A.SomeOtherProp = item.SomeOtherProp; 
    // perhaps "yield return item.A;" here 
} 

Wenn Sie taten LINQ-to-Objects, gibt es vielleicht einige Hacky Möglichkeiten, wie Sie es mit fließend tun könnte APIs - nicht schön, obwohl. (Edit - wie this other reply)

+0

Ich ziehe von einem DB, aber ich möchte nicht, dass diese Änderungen zurück in die DB gepostet werden, es ist nur erlaubt, dass dieses "neue" Objekt A einige andere Daten mit sich führt. – JPrescottSanders

1

Erweitern Sie Linq zunächst um eine Each-Option, indem Sie eine Klasse namens LinqExtensions erstellen.

Dann können Sie Join verwenden, um eine Liste neuer Objekte zurückzugeben, die die Originalobjekte mit dem entsprechenden Wert enthalten. Das Each wird über sie iterieren, so dass Sie jedem Objekt die Werte als Parameter zuweisen oder übergeben können.

Zuordnungsbeispiel:

objectA.Join(objectB,a=>a.Id,b=>b.Id,(a,b) => new {a,b.AValueIWant}).Each(o=>o.a.SomeProperty=o.AValueIWant); 

Parameterübergabe Beispiel:

objectA.Join(objectB,a=>a.Id,b=>b.Id,(a,b) => new {a,b.AValueIWant}).Each(o=>o.a.SomeMethod(o.AValueIWant)); 

Das Schöne daran ist, dass ObjectA und ObjectB müssen nicht vom gleichen Typ sein. Ich habe dies mit einer Liste von Objekten getan, die mit einem Dictionary verbunden sind (wie ein Lookup). Schlechte Sache ist es ist nicht klar, was vor sich geht. Es wäre besser, die Erweiterung Jeder zu überspringen und es so zu schreiben.

foreach(var change in objectA.Join(objectB,a=>a.Id,b=>b.Id,(a,b) => new {a,b.AValueIWant})) 
{ 
    change.a.SomeProperty = change.AValueIWant; 
    change.a.SomeMethod(change.AValueIWant); 
} 

Aber für mehr Klarheit würde ich wahrscheinlich tun:

foreach(var update in objectA.Join(objectB,objectA=>objectA.Id,objectB=>objectB.Id,(objectA,objectB) => new {objectA, Value = objectB.AValueIWant})) 
{ 
    update.objectA.SomeProperty = update.Value; 
} 

Sie müssen die ganze ObjectA in Ihrem neuen Objekt zurück, weil es nur lesbar und dies funktioniert der einzige Grund sein wird, liegt daran, Die Objekte in einer Sammlung werden referenziert, sodass Sie Änderungen an den Eigenschaften der Objekte vornehmen können.

Aber am Ende wäre es am klarsten zu überspringen die LINQ alle zusammen und nur durch die Sammlungen und suchen Sie nach Übereinstimmungen, wird dies mit der zukünftigen Wartung helfen. LINQ ist genial, aber genau wie wenn du einen Hammer hast, macht es nicht alles zum Nagel. Wenn du eine Sammlung hast, bedeutet das nicht, dass LINQ die Antwort ist.

1

Ich mache einen linken Join hier, also habe ich noch alle Daten von ObjektA, auch wenn die entsprechende Eigenschaft in objectB null ist. Wenn also die entsprechende Eigenschaft in objectB null ist, müssen Sie definieren, was in objectA zu tun ist. Ich benutze diese Aussage die ganze Zeit, um zwei Datensätze zu verbinden. Sie müssen nicht alle Eigenschaften in objectA erschöpfend auflisten und wie sie mappen, Sie müssen nur die Werte auflisten, die Sie mit objectB aktualisieren möchten. Vorhandene Werte in objectA sind sicher, sofern keine Zuordnung zu objectB definiert ist.

return from objectA in GetObjectAs() 
    join objectB in GetObjectBs() 
    on objectA.Id equals objectB.AId into combinedObj 
    from subObject in combinedObj.DefaultIfEmpty() 
    // update object A with object B data before selecting it 
    select ((Func<objectAType>)(() => 
    { 
     objectA.property = ((subObject == null) ? "Object B was null" : subObject.property); 
     objectA.property = ((subObject == null) ? "Object B was null" : subObject.property); 
     return objectA; 
    }))() 
0

Sie durch folgende ..

  var list1 = new List<ItemOne> 
         { 
          new ItemOne {IDItem = 1, OneProperty = "1"}, 
          new ItemOne {IDItem = 2, OneProperty = null}, 
          new ItemOne {IDItem = 3, OneProperty = "3"}, 
          new ItemOne {IDItem = 4, OneProperty = "4"} 
         }; 
     var list2 = new List<ItemTwo> 
         { 
          new ItemTwo {IDItem = 2, TwoProperty = "2"}, 
          new ItemTwo {IDItem = 3, TwoProperty = "3"}, 
         }; 


     var query = list1.Join(list2, l1 => l1.IDItem, l2 => l2.IDItem, (l1, l2) => 
     { 
      l1.OneProperty = l2.TwoProperty; 
      return l1; 
     });