我有两个对象,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;
答案 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;
});