简体   繁体   中英

What is the function evaluation requires all threads to run?

I just made a table Cust and in Ado.net and created an dbEntity to use LINQ

But I am getting this error and I am not able to fetch the records.

  protected void Page_Load(object sender, EventArgs e)
    {

        SSEntities db = new SSEntities();


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

    }

ConnectionString --

    <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" />

Error- function evaluation requires all threads to run

But this works

     protected void Page_Load(object sender, EventArgs e)
    {

        SSEntities db = new SSEntities();


        var a = db.Custs.FirstOrDefault();

    }

You'll have to be aware about the deferred execution that LINQ uses.

Assuming db.Custs is an object that implements IQueryable<Cust> or something similar.

If you check the type of a in your first example, you'll see that it is an IQueryable<Cust> . The one in your 2nd example is a Cust .

If you examine the LINQ methods, you'll notice that there are two groups of them: the ones that return IEnumerable<TResult> (or IQueryable<TResult> ) and the ones that don't.

Select, Join, GroupBy are examples of the first group. They don't execute the query. They don't represent fetched data, they represent the potential to select data and to enumerate it.

As long as you only concatenate functions from this group. the source of your data is not queried. This source is quite often a database, but it can be anything enumerable, CSV-file reader, JSON-files, information from the internet. In LINQ terms, we say that these methods use deferred execution. You can find this term at every description of the method.

Examples of methods from the second group are ToList, FirstOrDefault, Count, Any : the return is not an IQueryable<...> . Executing one of these methods will start enumerating the IEnumerable/IQueryable that is the input source: the first element will be fetched, and if there is one, and if needed for the method, other elements of the sequence will be fetched.

Back to your question

Your first page-load will create the query. The potential to fetch the data from your database is created. Alas, you forgot to execute the query. If you debug your program, and stop all threads at a breakpoint, and want to examine the value of a, you want to see the properties of object a . Alas, your debugger is willing to show you the results of simple properties, but contacting the database is too difficult for it.

Hence, if you really want to see the result of the database query while debugging, you'll have to execute the query, by adding a method of the second group. Most often people will temporarily add ToList() .

In your second example you used a method from the second group: the query was executed, and the result was put in local memory: the debugger can access the data, because it only has to check some memory.

So for debugging the solution is simple: add ToList , before examining.

Improvements

By now, you know that variable a in the first example expresses the potential to fetch data, not the fetched data itself. You obviously simplified your code for the question, you want to do something with the data.

  • I'm pretty sure that SSEntities implements IDisposable . You should Dispose it as soon as you don't need it anymore.
  • Make sure that you fetch the data (execute the query) before you dispose SSEntities.

Usually people use the following structure to make sure that the object is disposed properly in all circumstances:

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

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

Be aware for the following pitfall:

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

The query is not executed, yet you've disposed SSEntities. Your compiler won't complain, you'll get an exception at runtime.

The proper solution is to let your caller create and dispose the connection with the database, you only provide the selection:

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

Usage:

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM