这是我经常遇到的情况:我有父对象和子对象,而Child对象有一个Parent属性。我想运行一个获取子对象的查询,并将每个对象连接到正确的父对象:
Dim db = New DataContextEx()
get the children, along with the corresponding parent
Dim Children = From x In db.ChildTable
Join y In db.ParentTable
On x.ParentId Equals y.Id
Execute x.Parent = y <-- pseudocode
Select x
伪代码显示了我想要完成的任务:返回子对象x,但在执行(假)执行语句后返回代码。我可以想出很多方法来实现最终目标,但是他们都有更多的代码行和/或临时对象或函数的创建,我发现它们不够优雅。 (注意这是VB.NET语法,但它不是VB语法问题,因为AFAIK C#会有同样的问题。)
那么做我想做的最干净的方法是什么?
编辑:人们已经问过我正在使用的ORM,但这真的是一个普通的LINQ问题;我不是试图将其转换为逻辑以在服务器上运行,我只是想在服务器上运行查询后运行代码客户端一些语法糖。
答案 0 :(得分:11)
投影结果时,您可以使用匿名类型。 C#示例:
var items = from x In db.ChildTable
join y In db.ParentTable on x.ParentId equals y.Id
select new { Child =x , Parent=y };
然后分配父属性。
foreach(var item in items)
{
item.Child.Parent = item.Parent;
}
return items.Select(item => item.Child);
此外,您可能希望使用一些ORM解决方案,而不是自己动手。
答案 1 :(得分:2)
你可以这样做:
添加一个方法来为Child类执行逻辑,该类在vb中返回this
或Me
class Child
{
public Child GetWithAssignedParent(Parent y)
{
this.Parent = y;
return this;
}
}
在select查询中使用此方法来执行逻辑并返回Child类的更新实例:
var children = from x In db.ChildTable
join y In db.ParentTable on x.ParentId equals y.Id
select x.GetWithAssignedParent(y);
或使用Func&lt;&gt;
var children = from x in children
join y in parents on x.ParentId equals y.Id
select
new Func<Child>(() =>
{
x.Parent = y;
return x;
}).Invoke();
答案 2 :(得分:2)
这些建议,特别是@Paul's,非常有用,但我的最终版本不同,我将把它作为我自己的答案。
我实现了以下完全通用的扩展功能:
<Extension()> _
Public Function Apply(Of T)(ByVal Enumerable As IEnumerable(Of T), ByVal action As Action(Of T)) As IEnumerable(Of T)
For Each item In Enumerable
action(item)
Next
Return Enumerable
End Function
这与ForEach相同,只是它返回传入序列,我认为名称应用表明存在副作用。然后我可以将我的查询写成:
Dim Children = (
From x In db.ChildTable
Join y In db.ParentTable
On x.ParentId Equals y.Id
).
Apply(Sub(item) item.x.Parent = item.y).
Select(Function(item) item.x)
如果有一种方法可以使用自定义查询运算符当然会更好,所以我不必使用lambda语法,但即便如此,这似乎非常干净且可重用。再次感谢所有的帮助。
答案 3 :(得分:0)
这可能是最简单的解决方案:
var children = from x in db.ChildTable
join y in db.ParentTable
on x.ParentId equals y.Id
// Assign the Parent to the Child:
let parent = (x.Parent = y) // <-- Inline assignment (with a dummy variable "parent")
select x;
免责声明:此查询包含内联作业和修改状态 ...这两项都不被视为“最佳做法”。
但是,它易于阅读和理解,可维护,并且容易产生正确的结果,因此我认为这是一个很好的解决方案。
此外,这只适用于C#,因为VB.NET没有内联赋值。
答案 4 :(得分:0)
如果您正在使用LinqToObjects,请使用此代码将Parent指定给Children。
ILookup<int, Child> lookup = children.ToLookup(c => c.ParentId)
foreach(Parent p in parents)
{
foreach(Child c in lookup[p.Id])
{
c.Parent = p;
}
}
如果您使用的是LinqToSql,请使用DataLoadOptions加载相关记录。
如果您使用的是LinqToEntities,请使用.Include加载相关记录。