【问题标题】:What is the function evaluation requires all threads to run?什么是函数评估需要所有线程运行?
【发布时间】:2020-08-19 10:15:04
【问题描述】:

我刚刚在 Ado.net 中创建了一个表 Cust 并创建了一个 dbEntity 来使用 LINQ

但我收到此错误,我无法获取记录。

  protected void Page_Load(object sender, EventArgs e)
    {

        SSEntities db = new SSEntities();


        var a = from tb in db.Custs
                select tb;

    }

连接字符串 --

    <add name="SSEntities" connectionString="metadata=res://*/DbModel.csdl|res://*/DbModel.ssdl|res://*/DbModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=XYZ\SQLEXPRESS;initial catalog=SS;persist security info=True;user id=sa;password=La123;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

错误函数评估需要所有线程运行

但是这行得通

     protected void Page_Load(object sender, EventArgs e)
    {

        SSEntities db = new SSEntities();


        var a = db.Custs.FirstOrDefault();

    }

【问题讨论】:

  • “函数评估需要所有线程运行”是调试器的消息...当您看到该消息时,您想要实现什么?

标签: c# visual-studio linq


【解决方案1】:

您必须了解 LINQ 使用的延迟执行。

假设db.Custs 是一个实现IQueryable&lt;Cust&gt; 或类似的对象。

如果您在第一个示例中检查a 的类型,您会看到它是IQueryable&lt;Cust&gt;。第二个示例中的一个是Cust

如果您检查 LINQ 方法,您会注意到它们有两组:返回 IEnumerable&lt;TResult&gt;(或 IQueryable&lt;TResult&gt;)的一组和不返回的一组。

Select, Join, GroupBy 是第一组的示例。他们不执行查询。它们不代表获取的数据,它们代表选择数据和枚举数据的潜力。

只要您只连接该组中的函数。不查询您的数据来源。这个来源通常是一个数据库,但它可以是任何可枚举的、CSV 文件阅读器、JSON 文件、来自互联网的信息。在 LINQ 术语中,我们说这些方法使用延迟执行。您可以在该方法的每个描述中找到该术语。

第二组方法的示例是ToList, FirstOrDefault, Count, Any:返回不是IQueryable&lt;...&gt;。执行其中一个方法将开始枚举作为输入源的 IEnumerable/IQueryable:将获取第一个元素,如果有,并且如果方法需要,将获取序列的其他元素。

回到你的问题

您的第一个页面加载将创建查询。创造了从数据库中获取数据的潜力。唉,你忘了执行查询。如果您调试您的程序,并在断点处停止所有线程,并想检查 a 的值,您想查看对象 a 的属性。唉,你的调试器愿意向你展示简单属性的结果,但是联系数据库对它来说太难了。

因此,如果您真的想在调试时查看数据库查询的结果,则必须通过添加第二组的方法来执行查询。大多数情况下,人们会临时添加ToList()

在您的第二个示例中,您使用了第二组中的方法:执行查询,并将结果放入本地内存中:调试器可以访问数据,因为它只需要检查一些内存。

所以调试解决方案很简单:在检查之前添加ToList

改进

现在,您知道第一个示例中的变量a 表达了获取数据的可能性,而不是获取的数据本身。您显然简化了问题的代码,您想对数据做一些事情。

  • 我很确定 SSEntities 实现了IDisposable。您应该在不再需要它时立即将其丢弃。
  • 确保在处置 SSEntities 之前获取数据(执行查询)。

通常人们使用以下结构来确保对象在所有情况下都被正确处理:

using (SSEntities db = new SSEntities())
{
    var myQuery = db.Custs.Select(cust => new {...});

    // execute the query:
    var fetchedData = myQuery.ToList();
}

注意以下陷阱:

IQueryable<Cust> GetCustomers()
{
    using (SSEntities db = new SSEntities())
    {
        return db.Custs.Select(cust => new {...});
    }
}

查询未执行,但您已处置 SSEntities。你的编译器不会抱怨,你会在运行时得到一个异常。

正确的解决方案是让你的调用者创建和处理与数据库的连接,你只提供选择:

static IQueryable<Cust> GetCustomersByPostCode(this IQueryable<Cust> customers,
       PostCode postCode)
{
    return customers.Where(customer => customer.PostCode == postCode)
                    .Select(customer => new {...});
}

用法:

protected void Page_Load(object sender, EventArgs e)
{
    List<Customer> customers = null;
    using (SSEntities db = new SSEntities())
    {
    
        PostCode postCode = ...
        customers = db.Customers.GetCustomersByPostCode(postCode).ToList();
    }

    // the database is disposed, cannot be used anymore
    // customers already fetched, can still be used:
    ProcessFetchedCustomers(customers);
}

【讨论】:

    猜你喜欢
    • 2011-05-26
    • 2019-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-04
    • 2015-12-12
    相关资源
    最近更新 更多