2009-04-02 7 views
13

J'ai deux obects, A & B pour cette discussion. Je peux joindre ces objets (tables) via une relation commune ou une clé étrangère. J'utilise linq pour faire cette jointure et je veux seulement renvoyer ObjectA dans mon jeu de résultats; cependant, je voudrais mettre à jour une propriété de ObejctA avec des données d'ObjectB pendant la jointure de sorte que les ObjectAs que je sors de ma requête LINQ soient "légèrement" différents de leur état original dans le support de stockage choisi.LINQ Mise à jour de propriété de ligne pendant la jointure

Voici ma requête, vous pouvez voir que je voudrais juste pouvoir faire quelque chose comme objectA.SomeProperty = objectB.AValueIWantBadly

Je sais que je pouvais faire une nouvelle dans ma sélection et tourner de nouvelles OBjectAs , mais je voudrais éviter cela si possible et simplement mettre à jour un champ.

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; 

Répondre

22

Ajouter une méthode de mise à jour à votre ClassA

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

puis utilisez

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:

Ou utiliser une fonction lambda locale comme:

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

cela ne fonctionne pas pour linq-to-sql où j'ai une propriété qui possède l'attribut [NotMapped] ' – th1rdey3

0

pouvez-vous essayer l'instruction let? (pas sur ma machine à dev tester moi-même):

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

non, vous ne pouvez pas le faire; laissez seulement crée de nouvelles variables - il ne fait pas d'affectation. –

+0

J'ai essayé ceci le commentaire ci-dessus est correct ... non aller. – JPrescottSanders

2

Du mot "tables", il semble que vous obtenez ces données à partir d'une base de données. Dans quel cas; non: vous ne pouvez pas faire cela. Le plus proche que vous pouvez faire plût à sélectionner les objets et les colonnes supplémentaires, et mettre à jour les propriétés après:

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 
} 

Si vous faites LINQ à des objets, il y a peut-être des façons aki que vous pourriez faire avec Fluent APIs - pas joli, cependant. (Modifier - comme this other reply)

+0

Je tire d'une base de données, mais je ne veux pas que ces changements soient retournés à la base de données, c'est juste permettre à ce "nouvel" objet A de transporter des données différentes. – JPrescottSanders

1

D'abord étendre Linq pour avoir une Chaque option en créant une classe appelée LinqExtensions. Ensuite, vous pouvez utiliser Joindre pour renvoyer une liste de nouveaux objets contenant les objets d'origine avec la valeur appropriée. Chacun va itérer sur eux, vous permettant d'assigner ou de transmettre les valeurs en tant que paramètres à chaque objet.

Exemple d'affectation:

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

exemple de passage de paramètres:

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

La bonne chose à ce sujet est que ObjectA et ObjectB ne doivent pas être du même type. J'ai fait ceci avec une liste d'objets joints à un dictionnaire (comme une recherche). La mauvaise chose est que ce n'est pas clair ce qui se passe. Vous feriez mieux de sauter l'extension Chaque et de l'écrire comme ça.

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

Mais pour plus de clarté, je serais probablement faire:

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

Vous devez retourner l'ensemble ObjectA dans votre nouvel objet, car il sera en lecture seule et la seule raison pour laquelle cela fonctionne est parce que les objets d'une collection sont référencés vous permettant de modifier vos propriétés sur les objets. Mais à la fin, il serait plus facile d'ignorer la jointure LINQ et de faire une boucle dans les collections pour rechercher des correspondances, ce qui facilitera la maintenance future. LINQ est génial, mais comme lorsque vous avez un marteau, il ne fait pas tout un clou, quand vous avez une collection, cela ne veut pas dire que LINQ est la réponse.

1

Je fais une jointure à gauche ici, donc j'ai toujours toutes les données de objectA même si la propriété correspondante dans objectB est null. Donc, si la propriété correspondante dans l'objet B est nulle, vous devez définir ce qu'il faut faire dans objectA. J'utilise cette instruction tout le temps pour joindre deux ensembles de données. Vous n'avez pas besoin de répertorier de manière exhaustive toutes les propriétés de l'objet A et la façon dont elles sont mappées, il vous suffit de lister les valeurs que vous voulez mettre à jour avec objectB. Les valeurs préexistantes dans objectA sont sécurisées sauf si un mappage avec objectB est défini.

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

vous pouvez essayer en suivant ..

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