0

Hello I have just started to try and understand Parallel Linq and with my first attempt I am having no success. I am using EF 4.0 and a repository pattern class that I created to query the data. I don't believe that the repository pattern is the problem but I could be mistaken.

The database that I have isn't setup the way that I would like it but hey I inherited the system. The code that I am having the problem with is below:

            var gId = Sql.ToGuid(Request["ID"]);

            var lOrdersGridList = new OrdersGridList(); //Class that only contains properties

            var lOrdersForContact = new BaseRepository<ORDER>()
                .Find(i => i.ORDERS_CONTACTS.Where(b => b.CONTACT_ID == gId).Count() > 0).AsParallel()
                .Select(i =>
                    new OrdersGridList
                        {
                            ORDER_ID = i.ID,
                            ORDER_NUM = i.ORDER_NUM,
                            SHIPPING_ACCOUNT_ID = i.ORDERS_ACCOUNTS.Where(b =>  b.ORDER_ID == i.ID && b.ACCOUNT_ROLE == "Ship To").First().ACCOUNT_ID,
                            SHIPPING_ACCOUNT_NAME = i.ORDERS_ACCOUNTS.Where(b => b.ORDER_ID == i.ID && b.ACCOUNT_ROLE == "Ship To").First().ACCOUNT.NAME,
                            SHIPPING_CONTACT_ID = i.ORDERS_CONTACTS.Where(b => b.ORDER_ID == i.ID && b.CONTACT_ROLE == "Ship To").First().CONTACT_ID,
                            SHIPPING_CONTACT_NAME = i.ORDERS_CONTACTS.Where(b => b.ORDER_ID == i.ID && b.CONTACT_ROLE == "Ship To")
                                                                .Select(b => new { SHIPPING_CONTACT_NAME = (b.CONTACT.FIRST_NAME + ' ' + b.CONTACT.LAST_NAME) }).First().SHIPPING_CONTACT_NAME,
                            NAME = i.NAME

                        }).DefaultIfEmpty(lOrdersGridList).ToList<OrdersGridList>();


            grdMain.DataSource = lOrdersForContact.ToDataTable().DefaultView; //ToDataTable extension function converts the List Object to a datatable.

If I run the Code without AsParallel the code executes with no problem however, once I add AsParallel I receive the following error:

error message

Also just in case you wanted to see this is the class that I am declaring as new for the Select Above:

public class OrdersGridList : EntityObject
{
    public string ORDER_NUM { get; set; }

    public Guid ORDER_ID { get; set; }

    public Guid SHIPPING_ACCOUNT_ID { get; set; }

    public string SHIPPING_ACCOUNT_NAME { get; set; }

    public Guid SHIPPING_CONTACT_ID { get; set; }

    public string SHIPPING_CONTACT_NAME { get; set; }

    public string NAME { get; set; }
}

If I remove all of the relationships that are used to retrieve data in the select I don't receive any errors:

                var lOrdersForContact = new BaseRepository<ORDER>()
                .Find(i => i.ORDERS_CONTACTS.Where(b => b.CONTACT_ID == gId).Count() > 0).AsParallel()
                .Select(i =>
                    new OrdersGridList
                        {
                            ORDER_ID = i.ID,
                            ORDER_NUM = i.ORDER_NUM,
                            //SHIPPING_ACCOUNT_ID = i.ORDERS_ACCOUNTS.Where(b =>  b.ORDER_ID == i.ID && b.ACCOUNT_ROLE == "Ship To").First().ACCOUNT_ID,
                            //SHIPPING_ACCOUNT_NAME = i.ORDERS_ACCOUNTS.Where(b => b.ORDER_ID == i.ID && b.ACCOUNT_ROLE == "Ship To").First().ACCOUNT.NAME,
                            //SHIPPING_CONTACT_ID = i.ORDERS_CONTACTS.Where(b => b.ORDER_ID == i.ID && b.CONTACT_ROLE == "Ship To").First().CONTACT_ID,
                            //SHIPPING_CONTACT_NAME = i.ORDERS_CONTACTS.Where(b => b.ORDER_ID == i.ID && b.CONTACT_ROLE == "Ship To")
                            //                                    .Select(b => new { SHIPPING_CONTACT_NAME = (b.CONTACT.FIRST_NAME + ' ' + b.CONTACT.LAST_NAME) }).First().SHIPPING_CONTACT_NAME,
                            NAME = i.NAME

                        }).DefaultIfEmpty(lOrdersGridList).ToList<OrdersGridList>();

I would be more than happy to give more information if required. Any help you can provide on using PLinq I would appreciate it.

cjohns
  • 1,520
  • 2
  • 14
  • 21
  • `BaseRepository` is a wrapper around a `DbContext`? The dbcontext uses the LINQ query to construct the SQL expression to send down, so parallelizing the query is not helpful. – Tejs Nov 08 '12 at 16:26
  • 1
    From what I remember, it shares the same DbContext, which doesn't work on a parallel query since it opens and closes the connection during each parallel request. That being the case, it will fail, because you're using the same underlying connection and trying to open it multiple times (which doesn't work). – SPFiredrake Nov 08 '12 at 17:35
  • 1
    You should be able to parallelise a query (dependent on your provider), however I doubt PLinq knows how to. Your error seems to indicate this, the immediate cause that comes to mind is that the db doesn't support multiple query cacheing and hence a single provider can't provide parallel capabilities, its throwing an error when you try and open another connection. If you really need parallel capabilities you could just do it the old fashioned way by cloning the provider and then multi-threading the queries. – user1793607 Nov 08 '12 at 18:27

1 Answers1

0

To me it appears like the BaseRepository class creates some kind of LINQ to Entities query using the Find and Select parameters.

Using AsParellel is made for LINQ to Objects, where your code actually evaluates the expressions you pass. Other LINQ dialects, including LINQ to Entities, translate it into a different query language like SQL. The SQL server may do reasonable parallelisation itself.

Matthias Meid
  • 12,455
  • 7
  • 45
  • 79