更改了DataView数据查询的程序结构,继续调试。。。

This commit is contained in:
THINKPAD 2022-07-29 17:30:59 +08:00
parent 2d5570c2e9
commit 18e5585cc7
5 changed files with 195 additions and 133 deletions

View File

@ -5,6 +5,7 @@ using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Configuration;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -209,8 +210,46 @@ namespace MECF.Framework.UI.Client.CenterViews.DataLogs.DataHistory
VisibleRangeTime = new DateRange(StartDateTime.AddMinutes(-5), EndDateTime.AddMinutes(5));
ChartAutoRange = AutoRange.Always;
var colorRandom = new Random();
var colorPattern = GetNewColorPatternQueue();
// 生成待显示的数据列表
SelectedData.Clear();
#region 线
foreach (var module in selectedModules)
{
var selectedTerminal = module.Flatten(true).Where(x => x.Selected == true);
foreach (var terminal in selectedTerminal)
{
var line2D = new SicFastLineSeries(terminal.FullName)
{
AntiAliasing = true,
ResamplingMode = ResamplingMode.MinMax
};
// 确保当列队未空时不会出错,选择默认黑色。
var color = colorPattern.Any()
? colorPattern.Dequeue()
: Color.FromArgb(255, colorRandom.Next(0, 255), colorRandom.Next(0, 255),
colorRandom.Next(0, 255));
line2D.Stroke = System.Windows.Media.Color.FromRgb(color.R, color.G, color.B);
var ds = line2D.GetDataSeries();
ds.Tag = terminal;
SelectedData.Add(line2D);
}
}
#endregion
var dataSeriesList = SelectedData.Select(x => x.DataSeries).ToList();
BusyIndicatorContent = "Querying Data ...";
IsBusy = true;
_cancellationTokenSource = new CancellationTokenSource();
@ -221,14 +260,14 @@ namespace MECF.Framework.UI.Client.CenterViews.DataLogs.DataHistory
var ts = EndDateTime - StartDateTime;
if (ts.Days <= 1)
{
await Query(selectedModules, StartDateTime, EndDateTime, _cancellationTokenSource);
Query(selectedModules, dataSeriesList, StartDateTime, EndDateTime, _cancellationTokenSource);
}
else
{
var daySlices = Core.DateRange.SplitInToDays(new Core.DateRange(StartDateTime, EndDateTime));
foreach (var range in daySlices)
{
await Query(selectedModules, range.Start, range.End, _cancellationTokenSource);
Query(selectedModules, dataSeriesList, range.Start, range.End, _cancellationTokenSource);
if (_cancellationTokenSource.Token.IsCancellationRequested)
break;
@ -257,7 +296,7 @@ namespace MECF.Framework.UI.Client.CenterViews.DataLogs.DataHistory
/// <summary>
/// 查询数据
/// </summary>
public async Task Query(IEnumerable<ParameterNode> selectedModules, DateTime startTime, DateTime endTime,
public void Query(IEnumerable<ParameterNode> selectedModules, List<IDataSeries> dataSeriesList, DateTime startTime, DateTime endTime,
CancellationTokenSource cancellation)
{
var sw = new Stopwatch();
@ -267,7 +306,7 @@ namespace MECF.Framework.UI.Client.CenterViews.DataLogs.DataHistory
Debug.WriteLine("start to query data ....");
sw.Start();
#endif
var ds = await SearchDataBaseAsync(selectedModules, startTime, endTime, cancellation);
var ds = SearchDataBaseAsync(selectedModules, startTime, endTime, cancellation);
#if DEBUG
sw.Stop();
Debug.WriteLine($"Data returned, costs {sw.ElapsedMilliseconds}ms....");
@ -288,7 +327,8 @@ namespace MECF.Framework.UI.Client.CenterViews.DataLogs.DataHistory
Debug.WriteLine("start to render data ....");
sw.Restart();
#endif
await RenderChartAndTable(ds, cancellation);
var t = RenderChartAndTable(ds, cancellation, dataSeriesList);
Task.WaitAll(t.ToArray());
#if DEBUG
sw.Stop();
Debug.WriteLine($"Data render done, costs {sw.ElapsedMilliseconds}ms....");
@ -331,83 +371,80 @@ namespace MECF.Framework.UI.Client.CenterViews.DataLogs.DataHistory
/// 根据左侧选项查询数据
/// </summary>
/// <returns></returns>
private async Task<DataSet> SearchDataBaseAsync(IEnumerable<ParameterNode> modules, DateTime startTime, DateTime endTime, CancellationTokenSource cancellation)
private DataSet SearchDataBaseAsync(IEnumerable<ParameterNode> modules, DateTime startTime, DateTime endTime,
CancellationTokenSource cancellation)
{
if (cancellation == null)
throw new ArgumentNullException(nameof(cancellation), "cancellation object can not be null.");
var ds = new DataSet();
return await Task.Run(() =>
try
{
try
using (cancellation.Token.Register(Thread.CurrentThread.Abort))
{
using (cancellation.Token.Register(Thread.CurrentThread.Abort))
// 遍历模组
foreach (var module in modules)
{
// 遍历模组
foreach (var module in modules)
var sql = new StringBuilder();
//! 因为数据库中按天拆表无法一次性查询数据需使用UNION合并多表查询因此此处按天拼接SQL表达式
// 最终SQL表达式结构为
// (select xx from date1.xx) union (select xx from date2.xx) union (select xx from date3.xx)
// where time between xxx and xxx
// order by time asc
var ts = endTime - startTime;
for (var day = 0; day <= ts.Days; day++)
{
var sql = new StringBuilder();
//! 因为数据库中按天拆表无法一次性查询数据需使用UNION合并多表查询因此此处按天拼接SQL表达式
// 最终SQL表达式结构为
// (select xx from date1.xx) union (select xx from date2.xx) union (select xx from date3.xx)
// where time between xxx and xxx
// order by time asc
var ts = endTime - startTime;
for (var day = 0; day <= ts.Days; day++)
// 检查表名是否存在否则SQL执行出错。
var tblName = $"{startTime.AddDays(day):yyyyMMdd}.{module}";
if (CheckTableExists(tblName))
{
// 检查表名是否存在否则SQL执行出错。
var tblName = $"{startTime.AddDays(day):yyyyMMdd}.{module}";
if (CheckTableExists(tblName))
sql.Append("select \"time\" AS InternalTimeStamp");
var selectedParams = module.ChildNodes.FlattenNodes(true)
.Where(x => x.Selected == true);
// 添加待查询的列
foreach (var item in selectedParams)
{
sql.Append("select \"time\" AS InternalTimeStamp");
var selectedParams = module.ChildNodes.FlattenNodes(true)
.Where(x => x.Selected == true);
// 添加待查询的列
foreach (var item in selectedParams)
{
sql.Append("," + $"\"{item}\"");
}
sql.Append($" from \"{tblName}\" ");
if (day < ts.Days)
sql.Append(" UNION ");
sql.Append("," + $"\"{item}\"");
}
sql.Append($" from \"{tblName}\" ");
if (day < ts.Days)
sql.Append(" UNION ");
}
// 所有表名不可用,可能是日期范围错误
if (sql.Length <= 0)
{
continue;
}
sql.Append(
$" where \"time\" between {startTime.Ticks} and {endTime.Ticks} order by InternalTimeStamp asc");
// 查询数据并将返回的结果存储在DataSet中
var dataTable = QueryDataClient.Instance.Service.QueryData(sql.ToString());
//! 返回的 DataTable 可能不存在,原因是上述代码自动生成的表明可能不存在。
if (dataTable == null)
continue;
dataTable.TableName = module.Name;
ds.Tables.Add(dataTable);
}
// 所有表名不可用,可能是日期范围错误
if (sql.Length <= 0)
{
continue;
}
sql.Append(
$" where \"time\" between {startTime.Ticks} and {endTime.Ticks} order by InternalTimeStamp asc");
// 查询数据并将返回的结果存储在DataSet中
var dataTable = QueryDataClient.Instance.Service.QueryData(sql.ToString());
//! 返回的 DataTable 可能不存在,原因是上述代码自动生成的表明可能不存在。
if (dataTable == null)
continue;
dataTable.TableName = module.Name;
ds.Tables.Add(dataTable);
}
}
catch (ThreadAbortException)
{
// 操作被取消
ds = null;
throw;
}
}
catch (ThreadAbortException)
{
// 操作被取消
ds = null;
throw;
}
return ds;
}, cancellation.Token);
return ds;
}
/// <summary>
@ -415,7 +452,7 @@ namespace MECF.Framework.UI.Client.CenterViews.DataLogs.DataHistory
/// </summary>
/// <param name="ds"></param>
/// <exception cref="Exception"></exception>
private async Task RenderChartAndTable(DataSet ds, CancellationTokenSource cancellation)
private List<Task> RenderChartAndTable(DataSet ds, CancellationTokenSource cancellation, List<IDataSeries> dataSeriesList)
{
if (cancellation == null)
throw new ArgumentNullException(nameof(cancellation), "cancellation object can not be null.");
@ -429,10 +466,10 @@ namespace MECF.Framework.UI.Client.CenterViews.DataLogs.DataHistory
var appendTask = new List<Task>();
var colorRandom = new Random();
var colorPattern = GetNewColorPatternQueue();
/*var colorRandom = new Random();
var colorPattern = GetNewColorPatternQueue();*/
// 当曲线的数据点添加完毕时属性统计值。
/*// 当曲线的数据点添加完毕时属性统计值。
IProgress<XyDataSeries<DateTime, double>> seriesAppendDone = new Progress<XyDataSeries<DateTime, double>>(series =>
{
if (series.Tag is ParameterNode node)
@ -441,7 +478,7 @@ namespace MECF.Framework.UI.Client.CenterViews.DataLogs.DataHistory
node.MaxValue = node.RawData.Max(x => x.Value).ToString("F2");
node.AverageValue = node.RawData.Average(x => x.Value).ToString("F2");
}
});
});*/
// 一个Table一个模组
foreach (var table in ds.Tables.Cast<DataTable>())
@ -458,22 +495,24 @@ namespace MECF.Framework.UI.Client.CenterViews.DataLogs.DataHistory
var fullName = col.ColumnName;
// 在SelectedData中检查是否曲线已经存在若不存在新建一个
/*// 在SelectedData中检查是否曲线已经存在若不存在新建一个
var line2D = SelectedData.Cast<SicFastLineSeries>().FirstOrDefault(x => x.DataName == fullName);
if (line2D == null)
{
line2D = new SicFastLineSeries(fullName)
line2D = new SicFastLineSeries(fullName)
{
AntiAliasing = true,
ResamplingMode = ResamplingMode.MinMax
};
SelectedData.Add(line2D);
SelectedData.Add(line2D);
}
// 绑定LineChart对应的节点。
var node = ParameterNodes.FindTerminalByFullName(fullName);
// 确保当列队未空时不会出错,选择默认黑色。
var color = colorPattern.Any()
? colorPattern.Dequeue()
@ -481,89 +520,110 @@ namespace MECF.Framework.UI.Client.CenterViews.DataLogs.DataHistory
colorRandom.Next(0, 255));
line2D.Stroke = System.Windows.Media.Color.FromRgb(color.R, color.G, color.B);
var dataSeries = line2D.GetDataSeries();
var dataSeries = line2D.GetDataSeries();*/
var dataSeries =
dataSeriesList.FirstOrDefault(x => (x.Tag is ParameterNode node) && node.FullName == fullName);
if (dataSeries == null)
continue;
// ParameterNode放在line2D.DataSeries.Tag中而不是line2D.Tag中因为ParameterNode需要从Task中抛给seriesAppendDone
/*// ParameterNode放在line2D.DataSeries.Tag中而不是line2D.Tag中因为ParameterNode需要从Task中抛给seriesAppendDone
// 进行数据统计但Task中无法访问line2D对象因为跨线程访问问题。
dataSeries.Tag = node;
var rawData = node.RawData;
dataSeries.Tag = node;*/
var rawData = (dataSeries.Tag as ParameterNode)?.RawData;
if(rawData == null)
continue;
#endregion
#if DEBUG
Debug.WriteLine($"[{sw.ElapsedMilliseconds}ms] Appending point to series {line2D.DataName} ...");
Debug.WriteLine($"[{sw.ElapsedMilliseconds}ms] Appending point to series {fullName} ...");
#endif
//using (dataSeries.SuspendUpdates())
//{
var t = Task.Run(() =>
var t = Task.Run(() =>
{
#if DEBUG
Debug.WriteLine(
$"\t[{sw.ElapsedMilliseconds}ms] Start to appending data to {fullName} ...");
#endif
// 限制LineChart.Points数量提高显示速度。
const int RESTRICT_POINTS_IN_SERIES = 1000;
var rows = table.Rows;
var skippedRows = rows.Count / RESTRICT_POINTS_IN_SERIES;
if (skippedRows <= 0)
skippedRows = 1;
// 遍历数据行添加数据点到LineChart。
var skipped = 0;
var dateList = new List<DateTime>();
var valueList = new List<double>();
var metaList = new List<ParameterNodePoint>();
for (var i = 0; i < rows.Count; i++)
{
#if DEBUG
Debug.WriteLine(
$"\t[{sw.ElapsedMilliseconds}ms] Start to appending data to {line2D.DataName} ...");
#endif
var date = new DateTime(long.Parse(rows[i][0].ToString()));
var cellValue = rows[i][col];
var value = double.NaN;
// 限制LineChart.Points数量提高显示速度。
const int RESTRICT_POINTS_IN_SERIES = 1000;
if (cellValue is bool b)
value = b ? 1 : 0;
else if (double.TryParse(cellValue.ToString(), out var num))
value = num;
else
value = 0;
var rows = table.Rows;
var skippedRows = rows.Count / RESTRICT_POINTS_IN_SERIES;
if (skippedRows <= 0)
skippedRows = 1;
dateList.Add(date);
valueList.Add(value);
metaList.Add(new ParameterNodePoint(date, value));
// 遍历数据行添加数据点到LineChart。
var skipped = 0;
for (var i = 0; i < rows.Count; i++)
/*((XyDataSeries<DateTime, double>)dataSeries).Append(date, value, new ParameterNodePoint(date, value));
rawData.Add(new ParameterNodePoint(date, value));*/
/*// Re-sampling to improve the rendering performance.
if (skipped >= skippedRows)
{
var date = new DateTime(long.Parse(rows[i][0].ToString()));
var cellValue = rows[i][col];
var value = double.NaN;
if (cellValue is bool b)
value = b ? 1 : 0;
else if (double.TryParse(cellValue.ToString(), out var num))
value = num;
else
value = 0;
dataSeries.Append(date, value, new ParameterNodePoint(date, value));
rawData.Add(new ParameterNodePoint(date, value));
/*// Re-sampling to improve the rendering performance.
if (skipped >= skippedRows)
{
dataSeries.Append(date, value, new ParameterNodePoint(date, value));
skipped = 0;
}
else
{
skipped++;
}*/
// 操作被取消
if (cancellation.Token.IsCancellationRequested)
return;
//Thread.Sleep(1);
skipped = 0;
}
else
{
skipped++;
}*/
//
seriesAppendDone.Report(dataSeries);
// 操作被取消
if (cancellation.Token.IsCancellationRequested)
return;
//Thread.Sleep(1);
}
//
//seriesAppendDone.Report(dataSeries);
using (dataSeries.SuspendUpdates())
{
((XyDataSeries<DateTime, double>)dataSeries).Append(dateList, valueList, metaList);
}
#if DEBUG
Debug.WriteLine(
$"\t[{sw.ElapsedMilliseconds}ms] Finish appending data to {line2D.DataName}!");
$"\t[{sw.ElapsedMilliseconds}ms] Finish appending data to {fullName}!");
#endif
});
});
appendTask.Add(t);
appendTask.Add(t);
//}
//await Task.Delay(100);
@ -575,7 +635,7 @@ namespace MECF.Framework.UI.Client.CenterViews.DataLogs.DataHistory
#endif
// 等待所有序列写入数据完成。
await Task.WhenAll(appendTask);
//await Task.WhenAll(appendTask);
//}
@ -585,6 +645,8 @@ namespace MECF.Framework.UI.Client.CenterViews.DataLogs.DataHistory
Debug.WriteLine($"[{sw.ElapsedMilliseconds}ms] Method {nameof(RenderChartAndTable)} Done");
sw.Stop();
#endif
return appendTask;
}
#region Parameter Grid Control