使用LINQ选择和组合对象的正确方法是什么?

时间:2011-12-28 18:17:30

标签: .net linq

这是我经常遇到的情况:我有父对象和子对象,而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问题;我不是试图将其转换为逻辑以在服务器上运行,我只是想在服务器上运行查询后运行代码客户端一些语法糖。

5 个答案:

答案 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中返回thisMe

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加载相关记录。