Winforms 需要在后台工作人员中处理Linq-2-SQL重载响应
我在这里有点进退两难。我已启用此BackgroundWorker设置: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
#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()将流划分为块,我将如何“添加”到网格中?