在加入期间LINQ在线属性更新

时间:2009-04-02 12:44:52

标签: c# linq

我有两个对象,A& B对于这个讨论。我可以通过公共关系或外键加入这些对象(表)。我使用linq来做这个连接,我只想在结果集中返回ObjectA;但是,我想在连接期间用ObjectB中的数据更新ObejctA的属性,这样我从LINQ查询中获取的ObjectAs与它们在所选存储介质中的原始状态“略有”不同。

这是我的查询,你可以看到我只想做一些像objectA.SomeProperty = objectB.AValueIWantBadly

我知道我可以在我的选择中创建一个新的并启动新的OBjectAs,但我想尽可能避免这种情况,只需更新一个字段。

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;

6 个答案:

答案 0 :(得分:24)

为您的ClassA添加更新方法

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

然后使用

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

修改

或使用本地lambda函数,如:

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

答案 1 :(得分:2)

从“表格”这个词来看,听起来好像是从数据库中获取这些数据。在这种情况下;不:你不能这样做。您可以做的最接近的事情是选择对象和额外的列,然后更新属性:

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
}

如果您正在使用LINQ-to-Objects,可能有一些hacky方法可以使用流畅的API来完成它 - 不过很好。 (编辑 - 如this other reply

答案 2 :(得分:1)

首先通过创建一个名为LinqExtensions的类来扩展Linq以获得每个选项。

  public static class LinqExtensions
  {
    public static void Each<T>(this IEnumerable<T> source, Action<T> method)
    {
      foreach (var item in source)
      {
        method(item);
      }
    }
  }

然后,您可以使用Join返回包含具有适当值的原始对象的新对象列表。每个都将迭代它们,允许您将值作为参数分配或传递给每个对象。

作业示例:

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

参数传递示例:

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

关于这一点的好处是ObjectA和ObjectB不必是同一类型。我已经使用加入Dictionary的对象列表(如查找)完成了此操作。不好的是,目前还不清楚发生了什么。你最好跳过每个扩展,然后像这样写。

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

但为了更清楚,我可能会这样做:

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

您需要在新对象中返回整个ObjectA,因为它只是readonly而且唯一的原因是因为引用了集合中的对象,允许您对对象的属性进行更改。

但最终,最好是一起跳过LINQ连接并循环浏览集合并寻找匹配,这将有助于未来的维护。 LINQ非常棒,但就像你拿锤子一样,它不会让一切都成为钉子,当你有一个集合时,它并不意味着LINQ就是答案。

答案 3 :(得分:1)

我正在这里进行左连接,所以即使objectB中的相应属性为null,我仍然拥有来自objectA的所有数据。因此,如果objectB中的相应属性为null,则必须定义在objectA中要执行的操作。我一直使用这个语句来连接两组数据。您不需要详尽地列出objectA中的所有属性以及它们如何映射,您只需要列出要使用objectB更新的值。除非定义了到objectB的映射,否则objectA中预先存在的值是安全的。

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

答案 4 :(得分:0)

你可以试试let语句吗? (不是在我的开发机器上自己测试一下):

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

答案 5 :(得分:0)

您可以尝试遵循..

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