当从 linq 查询创建 IQueryable 时,为什么它不是一个“新”查询?多变的?

发布于 2024-08-08 13:27:14 字数 1424 浏览 5 评论 0原文

我正在使用实体框架,并有一个循环查看一组人员,并使用 foreach 循环创建每个人地址的查询。创建每个地址查询时,它都会添加到树视图的节点中,稍后可以使用它(以填充子节点):

 IQueryable<Person> pQuery = (IQueryable<Person>)myContext.People; //get a list of people

 //go through and get the set of addresses for each person
 foreach (var p in pQuery)
 {
      var addressQuery = from a in myContext.Addresses
                                   from al in a.Address_Links
                                   where al.P_ID == p.P_ID
                                   orderby a.A_POST_CODE
                                   select a;


     //add the query to a TreeView node (use the tag to store it)
     TreeNode newNode = new TreeNode();
     newNode.Tag = addressQuery;
 }

现在,我在运行应用程序时发现的问题是所有查询都是最后创建的查询即循环的最后一次迭代。这就像在循环的第一次迭代中创建addressQuery,然后在每个后续查询中覆盖它。这样做的结果是,树节点中的所有地址查询都是对最后一个查询的引用(?)

进一步调查,我可以通过使用静态类生成地址查询并将其传递到每个TreeNode,如下:

 public static class Queries
    {
        public static IQueryable<Address> AddressesForPerson(GenesisEntities myContext, int key)
        {
            var query = from a in myContext.Addresses
                        from al in a.Address_Links
                        where al.P_ID == key
                        orderby a.A_POST_CODE
                        select a;
            return query;
        }

}

我的问题是我对这种行为感到困惑。为什么静态查询类对我有帮助?谁能向我解释这是怎么回事?

困惑.com!

I am using the Entity Framework and have got a loop that looks at a set of People and using a foreach loop creates a query for the address of each person. As each address query is created it is added to the node of a treeview where it can be later used (to populate children nodes):

 IQueryable<Person> pQuery = (IQueryable<Person>)myContext.People; //get a list of people

 //go through and get the set of addresses for each person
 foreach (var p in pQuery)
 {
      var addressQuery = from a in myContext.Addresses
                                   from al in a.Address_Links
                                   where al.P_ID == p.P_ID
                                   orderby a.A_POST_CODE
                                   select a;


     //add the query to a TreeView node (use the tag to store it)
     TreeNode newNode = new TreeNode();
     newNode.Tag = addressQuery;
 }

Now, the problem that I am finding upon running the app is that ALL the queries are the last query created i.e. the last iteration of the loop. It is like the addressQuery is created on the first iteration of the loop and then overwritten on each subsequent query. The result of this is that it is like all the address queries in the treenodes are references to the last query made(?)

Further investigation that I could solve the problem by using a static class to generate the address query and pass that into each the TreeNode, as follows:

 public static class Queries
    {
        public static IQueryable<Address> AddressesForPerson(GenesisEntities myContext, int key)
        {
            var query = from a in myContext.Addresses
                        from al in a.Address_Links
                        where al.P_ID == key
                        orderby a.A_POST_CODE
                        select a;
            return query;
        }

}

The question I have is that I am baffled by this behaviour. Why does having a static query class help me? Can anyone explain to me what is going on?

Confused.Com!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

月亮邮递员 2024-08-15 13:27:14

原因是 p 变量(foreach 循环变量)被捕获并且查询被延迟计算。因此,当查询实际运行时,它使用当时 p 变量的当前值,即最后一个值。阅读我对“a的确切定义是什么”的回答关闭?” 了解更多信息。

要解决这个问题,只需尝试引入一个临时变量:

 // `loopVariable` is scoped inside loop body AND the loop declaration.
 foreach (var loopVariable in pQuery) 
 {
      var p = loopVariable; // This variable is scoped **inside** loop body.
      var addressQuery = from a in myContext.Addresses
                                   from al in a.Address_Links
                                   where al.P_ID == p.P_ID
                                   orderby a.A_POST_CODE
                                   select a;


     //add the query to a TreeView node (use the tag to store it)
     myTreeView.Tag = addressQuery
 }

The reason is that the p variable (the foreach loop variable) is captured and the query is evaluated lazily. As a result, when the query is actually run, it uses the current value of p variable at that time, which is the last value. Read my answer to "What is the exact definition of a closure?" for more info.

To solve the problem, simply try introducing a temporary variable:

 // `loopVariable` is scoped inside loop body AND the loop declaration.
 foreach (var loopVariable in pQuery) 
 {
      var p = loopVariable; // This variable is scoped **inside** loop body.
      var addressQuery = from a in myContext.Addresses
                                   from al in a.Address_Links
                                   where al.P_ID == p.P_ID
                                   orderby a.A_POST_CODE
                                   select a;


     //add the query to a TreeView node (use the tag to store it)
     myTreeView.Tag = addressQuery
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文