Winforms 需要在后台工作人员中处理Linq-2-SQL重载响应

Winforms 需要在后台工作人员中处理Linq-2-SQL重载响应,winforms,linq-to-sql,c#-4.0,Winforms,Linq To Sql,C# 4.0,我在这里有点进退两难。我已启用此BackgroundWorker设置: #region Locum List private Object DoWorkMain_LocumList() { #region Query var locums = from locum in DbContext.Locums where

我在这里有点进退两难。我已启用此BackgroundWorker设置:

    #region Locum List
    private Object DoWorkMain_LocumList() {
        #region Query
        var locums = from locum in DbContext.Locums
                                 where
                                    locum.IsActive == true &&
                                    locum.IsAdminMarkedComplete == true &&
                                    locum.IsLocumsExciteBan == false &&
                                    locum.IsGPHCBan == false &&
                                    locum.LocumWorkingPreferenceID == 1
                                 select new {
                                     LocumID = locum.OID,
                                     LocumName = locum.FirstName + " " + locum.LastName,
                                     locum.MobileNumber,
                                     locum.Email,
                                     Gender = locum.Gender ? "Male" : "Female",
                                     locum.DateofBirth,
                                     LocumType = locum.LocumType.Name,
                                     Distance = DbContext.GetDistanceFromCache(TextAddressPostCode.Text.Trim(), locum.AddressInfo.Postcode),
                                     Address = String.Format("{0} {1} {2} {3}",
                                                            locum.AddressInfo.House.Length == 0 ? String.Empty : locum.AddressInfo.House + ", ",
                                                            locum.AddressInfo.Street.Length == 0 ? String.Empty : locum.AddressInfo.Street + ", ",
                                                            locum.AddressInfo.Area.Length == 0 ? String.Empty : locum.AddressInfo.Area + ", ",
                                                            locum.AddressInfo.Postcode ?? String.Empty),
                                     Postcode = locum.AddressInfo.Postcode,
                                     City = locum.AddressInfo.City.Name,
                                     County = locum.AddressInfo.City.County.Name,
                                     locum.SystemUserID,
                                     Status = DbContext.GetJobPermanentProcessLatestStatus(VaccanyID, locum.OID)
                                 };
        #endregion

        DataTable LocumListX = new DataTable("LocumList");
        DataColumn PrimaryColumn = LocumListX.Columns.Add("LocumID", typeof(Int64));
        LocumListX.Columns.Add("LocumName", typeof(String));
        LocumListX.Columns.Add("MobileNumber", typeof(String));
        LocumListX.Columns.Add("Email", typeof(String));
        LocumListX.Columns.Add("Gender", typeof(String));
        LocumListX.Columns.Add("DateofBirth", typeof(DateTime));
        LocumListX.Columns.Add("LocumType", typeof(String));
        LocumListX.Columns.Add("Distance", typeof(Decimal));
        LocumListX.Columns.Add("Address", typeof(String));
        LocumListX.Columns.Add("Postcode", typeof(String));
        LocumListX.Columns.Add("City", typeof(String));
        LocumListX.Columns.Add("County", typeof(String));
        LocumListX.Columns.Add("SystemUserID", typeof(Int64));
        LocumListX.Columns.Add("Status", typeof(String));

        LocumListX.PrimaryKey = new DataColumn[] { PrimaryColumn };

        int iCurrentRowIndex = 0;

        #region DataTable
        int LocumListXRowsCount = locums.Count();

        foreach (var item in locums) {
            DataRow newRow = LocumListX.NewRow();

            newRow["LocumID"] = item.LocumID;
            newRow["LocumName"] = item.LocumName;
            newRow["MobileNumber"] = item.MobileNumber;
            newRow["Email"] = item.Email;
            newRow["Gender"] = item.Gender;
            newRow["DateofBirth"] = item.DateofBirth;
            newRow["LocumType"] = item.LocumType;
            newRow["Distance"] = item.Distance;
            newRow["Address"] = item.Address;
            newRow["Postcode"] = item.Postcode;
            newRow["City"] = item.City;
            newRow["County"] = item.County;
            newRow["SystemUserID"] = item.SystemUserID;
            newRow["Status"] = item.Status;

            LocumListX.Rows.Add(newRow);

            iCurrentRowIndex++;
            BackgroundWorkerLocumList.ReportProgress((int)(iCurrentRowIndex * 100F / (LocumListXRowsCount - 1)));
        }
        #endregion

        LocumListXRowsCount = LocumListX.Rows.Count;
        iCurrentRowIndex = 0;

        foreach (DataRow Row in LocumListX.Rows) {
            if (Convert.ToDecimal(Row["Distance"]) >= 0) {
                iCurrentRowIndex++;
                continue;
            }

            Row["Distance"] = GetDistanceBetween(Row);

            iCurrentRowIndex++;
            BackgroundWorkerLocumList.ReportProgress((int)(iCurrentRowIndex * 100F / (LocumListXRowsCount - 1)));

            if (BackgroundWorkerLocumList.CancellationPending) {
                return null;
            }
        }

        return LocumListX;
    }

    private void BackgroundWorkerLocumList_DoWork(object sender, DoWorkEventArgs e) {
        BackgroundWorker backgroundWorkerLocumList = sender as BackgroundWorker;

        try {
            if (backgroundWorkerLocumList != null) {
                backgroundWorkerLocumList.ReportProgress(0);

                if (backgroundWorkerLocumList.CancellationPending) {
                    e.Cancel = true;
                    return;
                }

                e.Result = DoWorkMain_LocumList();
            }
        }
        catch (Exception ex) {
            e.Result = ex;
        }
    }

    private void BackgroundWorkerLocumList_ProgressChanged(object sender, ProgressChangedEventArgs e) {
        ProgressBarLocumList.EditValue = e.ProgressPercentage;
    }

    private void BackgroundWorkerLocumList_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
        LoadLocumList_ResetProgress();

        if (e.Cancelled) {
            XtraMessageBox.Show("The task has been canceled");
        }
        else if (e.Error != null) {
            FormHelpers.ShowErrorMessageBox("Error while looking up distances.", Text, e.Error);
        }
        else {
            #region Grid
            GridLocumList.DataSource = e.Result as DataTable;
            LoadLocumListGridSetup();
            #endregion
        }

        ButtonRefreshLocumList.Enabled = true;
    }
    #endregion
实际情况是,原始LINQ应该返回1000到1500条记录。因此,在稍后的阶段,我对每个线程执行一次For-Each操作,以将LINQ转换为数据表(
foreach(rocms中的var项)
),我会遇到严重的暂停,很快,线程就会在没有任何警告的情况下死亡。我正在手动将LINQ转换为DataTable,因为我以前使用过MoreLinq扩展方法,但这也花了很长时间,完全没有进度报告,而且我的客户不喜欢

我有两个想法,第三个是严重的头痛

第一:如果我能用where子句枚举结果。唯一的列是LocumID。如果我可以先从1000-1500个结果中创建一个所有Loommid的列表,然后对列表中的每个Loommid使用,这样我就可以一次处理一行LINQ来构建我的数据表

第二个:实现.Skip()和.Take()以50块的形式处理数据

有什么建议吗


关于。

由于不应轻视多线程应用程序,因此我将简要介绍如何看待此问题,并在并发问题出现时避免使用代码

基本上,我将从一个集合(an)开始,以保存网格将要保存的对象的实际集合

然后,在工作线程中,我将启动您的循环以加载数据。使用.Skip()/.Take()和索引器跟踪当前页面:

...

const int PageSize = 50;  // Or whatever you find works best, of course
int CurrentPage = 0;
int ReturnedCount = 0;

do
{
    var ReturnedData = GetNextSetOfData (CurrentPage, PageSize);
    ReturnedCount = ReturnedData.Count ();

    StoreReturnedData (ReturnedData);

    ++CurrentPage;
}
while (ReturnedCount > 0)

...

object GetNextSetOfData (int Page, int PageSize)
{
    var MyQuery = // Place your LINQ query here and add
                  // .Skip (Page * PageSize).Take (PageSize)
                  // and return the result;

    return MyQuery;
}

...

void StoreReturnedData (object Data)
{
    // Append your data to the end of the ObservableCollection (or whatever you're using)
    // here.  Be sure to use locks where you need to and all the tools to communicate
    // concurrently with your program
}
如果您选择observable路径,那么您只需拥有一个偶数来处理更新,获取对象,用它们创建行,然后将它们添加到DataTable,然后将它们从ObservableCollection中删除。当然,可以在加载数据时使DataTable为只读,这样用户就不会在添加行时开始处理数据

不过,问题是,您处理的是并发性,正如您所知,这很容易搞砸,而且我不是这方面的专家,因此我将避免任何形式的讨论


由于您的查询非常繁重,而且被调用的次数太多,因此我也会考虑制作一个示例来帮助加快查询速度。

就我个人而言,我会尝试第二个选项,因为您可以。Skip()/.Take()稍后,改变区块并微调性能。请尽可能简短地写下您的主要问题。thanks@jdangelo有没有显示正确的跳转机制的页面从一个线程化的aproach更新一个网格?问候。@Hassan-这会有点困难,因为我不确定您的应用程序是如何运行的,以及您希望发生什么。是否要将所有表加载到内存中?数据库是本地的还是您正在通过线路进行呼叫?再详细一点,我就可以试着帮助一些人了。@jdangelo我需要处理从Linq查询返回的全部数据。正如您可能从
BackgroundWorkerLocumList\u RunWorkerCompleted
事件中看到的,我希望将整个数据表绑定到网格。我眼前的问题是,如果我以某种方式使用.Skip()/.Take()将流划分为块,我将如何“添加”到网格中?