优化导入excel效率

This commit is contained in:
Kimdiego2098
2023-07-25 14:21:17 +08:00
parent 18eddf4700
commit aadbe05a5e
26 changed files with 1424 additions and 586 deletions

View File

@@ -362,13 +362,13 @@ namespace ThingsGateway.Foundation.Adapter.Siemens
var result1 = SendThenResponse(ISO_CR);
if (!result1.IsSuccess)
{
Logger?.Error(client.IP + ":" + client.Port + "ISO初始化失败");
Logger?.Warning(client.IP + ":" + client.Port + "-ISO初始化失败" + result1.Message);
return;
}
var result2 = SendThenResponse(S7_PN);
if (!result2.IsSuccess)
{
Logger?.Error(client.IP + ":" + client.Port + "初始化失败");
Logger?.Warning(client.IP + ":" + client.Port + "-初始化失败");
return;
}
pdu_length = ThingsGatewayBitConverter.ToUInt16(result2.Content.SelectLast(2), 0);

View File

@@ -43,13 +43,14 @@ public abstract class S7 : CollectBase
public override Task AfterStopAsync()
{
_plc?.Disconnect();
if (_plc != null)
_plc?.Disconnect();
return Task.CompletedTask;
}
public override async Task BeforStartAsync(CancellationToken cancellationToken)
{
await _plc.ConnectAsync(cancellationToken);
await _plc?.ConnectAsync(cancellationToken);
}
protected override void Dispose(bool disposing)

View File

@@ -18,13 +18,12 @@ public class ImportPreviewOutputBase
/// 是否有错误
/// </summary>
public bool HasError { get; set; }
public virtual int DataCount { get; }
public virtual List<(int row, bool isSuccess, string resultString)> Results { get; set; } = new();
public int DataCount { get => Results.Count; }
public TGConcurrentList<(int row, bool isSuccess, string resultString)> Results { get; set; } = new();
}
public class ImportPreviewOutput<T> : ImportPreviewOutputBase where T : class
{
public override int DataCount { get => Data == null ? 0 : Data.Count; }
public List<T> Data { get; set; } = new();
public Dictionary<string, T> Data { get; set; } = new();
}

View File

@@ -0,0 +1,688 @@
#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Linq;
namespace ThingsGateway.Core;
/// <summary>
/// 线程安全的List其基本操作和List一致。
/// </summary>
/// <typeparam name="T"></typeparam>
public class TGConcurrentList<T> : IList<T>
{
private readonly List<T> m_list;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="collection"></param>
public TGConcurrentList(IEnumerable<T> collection)
{
m_list = new List<T>(collection);
}
/// <summary>
/// 构造函数
/// </summary>
public TGConcurrentList()
{
m_list = new List<T>();
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="capacity"></param>
public TGConcurrentList(int capacity)
{
m_list = new List<T>(capacity);
}
/// <summary>
/// 元素数量
/// </summary>
public int Count
{
get
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.Count;
}
}
}
/// <summary>
/// 是否为只读
/// </summary>
public bool IsReadOnly => false;
/// <summary>
/// 获取索引元素
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public T this[int index]
{
get
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list[index];
}
}
set
{
lock (((ICollection)m_list).SyncRoot)
{
m_list[index] = value;
}
}
}
/// <summary>
/// 添加元素
/// </summary>
/// <param name="item"></param>
public void Add(T item)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Add(item);
}
}
/// <summary>
/// 清空所有元素
/// </summary>
public void Clear()
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Clear();
}
}
/// <summary>
/// 是否包含某个元素
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Contains(T item)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.Contains(item);
}
}
/// <summary>
/// 复制到
/// </summary>
/// <param name="array"></param>
/// <param name="arrayIndex"></param>
public void CopyTo(T[] array, int arrayIndex)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.CopyTo(array, arrayIndex);
}
}
/// <summary>
/// 返回迭代器
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.ToList().GetEnumerator();
}
}
/// <summary>
/// 返回迭代器组合
/// </summary>
/// <returns></returns>
IEnumerator IEnumerable.GetEnumerator()
{
lock (((ICollection)m_list).SyncRoot)
{
return GetEnumerator();
}
}
/// <summary>
/// 索引
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public int IndexOf(T item)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.IndexOf(item);
}
}
/// <summary>
/// 插入
/// </summary>
/// <param name="index"></param>
/// <param name="item"></param>
public void Insert(int index, T item)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Insert(index, item);
}
}
/// <summary>
/// 移除元素
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Remove(T item)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.Remove(item);
}
}
/// <summary>
/// 按索引移除
/// </summary>
/// <param name="index"></param>
public void RemoveAt(int index)
{
lock (((ICollection)m_list).SyncRoot)
{
if (index < m_list.Count)
{
m_list.RemoveAt(index);
}
}
}
/// <summary>
/// 获取或设置容量
/// </summary>
public int Capacity
{
get
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.Capacity;
}
}
set
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Capacity = value;
}
}
}
/// <summary>
/// <inheritdoc cref="List{T}.AddRange(IEnumerable{T})"/>
/// </summary>
/// <param name="collection"></param>
public void AddRange(IEnumerable<T> collection)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.AddRange(collection);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.BinarySearch(T)"/>
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public int BinarySearch(T item)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.BinarySearch(item);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.BinarySearch(T, IComparer{T})"/>
/// </summary>
/// <param name="item"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public int BinarySearch(T item, IComparer<T> comparer)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.BinarySearch(item, comparer);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.BinarySearch(int, int, T, IComparer{T})"/>
/// </summary>
/// <param name="index"></param>
/// <param name="count"></param>
/// <param name="item"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public int BinarySearch(int index, int count, T item, IComparer<T> comparer)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.BinarySearch(index, count, item, comparer);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.ConvertAll{TOutput}(Converter{T, TOutput})"/>
/// </summary>
/// <typeparam name="TOutput"></typeparam>
/// <param name="converter"></param>
/// <returns></returns>
public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.ConvertAll(converter);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.Find(Predicate{T})"/>
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
public T Find(Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.Find(match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindAll(Predicate{T})"/>
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
public List<T> FindAll(Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindAll(match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindIndex(int, int, Predicate{T})"/>
/// </summary>
/// <param name="startIndex"></param>
/// <param name="count"></param>
/// <param name="match"></param>
/// <returns></returns>
public int FindIndex(int startIndex, int count, Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindIndex(startIndex, count, match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindIndex(int, Predicate{T})"/>
/// </summary>
/// <param name="startIndex"></param>
/// <param name="match"></param>
/// <returns></returns>
public int FindIndex(int startIndex, Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindIndex(startIndex, match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindIndex(Predicate{T})"/>
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
public int FindIndex(Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindIndex(match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindLast(Predicate{T})"/>
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
public T FindLast(Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindLast(match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindLastIndex(int, int, Predicate{T})"/>
/// </summary>
/// <param name="startIndex"></param>
/// <param name="count"></param>
/// <param name="match"></param>
/// <returns></returns>
public int FindLastIndex(int startIndex, int count, Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindLastIndex(startIndex, count, match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindLastIndex(int, Predicate{T})"/>
/// </summary>
/// <param name="startIndex"></param>
/// <param name="match"></param>
/// <returns></returns>
public int FindLastIndex(int startIndex, Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindLastIndex(startIndex, match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindLastIndex(Predicate{T})"/>
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
public int FindLastIndex(Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindLastIndex(match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.ForEach(Action{T})"/>
/// </summary>
/// <param name="action"></param>
public void ForEach(Action<T> action)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.ForEach(action);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.GetRange(int, int)"/>
/// </summary>
/// <param name="index"></param>
/// <param name="count"></param>
/// <returns></returns>
public List<T> GetRange(int index, int count)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.GetRange(index, count);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.IndexOf(T, int)"/>
/// </summary>
/// <param name="item"></param>
/// <param name="index"></param>
/// <returns></returns>
public int IndexOf(T item, int index)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.IndexOf(item, index);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.IndexOf(T, int, int)"/>
/// </summary>
/// <param name="item"></param>
/// <param name="index"></param>
/// <param name="count"></param>
/// <returns></returns>
public int IndexOf(T item, int index, int count)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.IndexOf(item, index, count);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.InsertRange(int, IEnumerable{T})"/>
/// </summary>
/// <param name="index"></param>
/// <param name="collection"></param>
public void InsertRange(int index, IEnumerable<T> collection)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.InsertRange(index, collection);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.LastIndexOf(T)"/>
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public int LastIndexOf(T item)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.IndexOf(item);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.LastIndexOf(T, int)"/>
/// </summary>
/// <param name="item"></param>
/// <param name="index"></param>
/// <returns></returns>
public int LastIndexOf(T item, int index)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.LastIndexOf(item, index);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.LastIndexOf(T, int, int)"/>
/// </summary>
/// <param name="item"></param>
/// <param name="index"></param>
/// <param name="count"></param>
/// <returns></returns>
public int LastIndexOf(T item, int index, int count)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.LastIndexOf(item, index, count);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.RemoveAll(Predicate{T})"/>
/// </summary>
/// <param name="match"></param>
public void RemoveAll(Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.RemoveAll(match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.RemoveRange(int, int)"/>
/// </summary>
/// <param name="index"></param>
/// <param name="count"></param>
public void RemoveRange(int index, int count)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.RemoveRange(index, count);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.Reverse()"/>
/// </summary>
public void Reverse()
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Reverse();
}
}
/// <summary>
/// <inheritdoc cref="List{T}.Reverse(int, int)"/>
/// </summary>
/// <param name="index"></param>
/// <param name="count"></param>
public void Reverse(int index, int count)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Reverse(index, count);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.Sort()"/>
/// </summary>
public void Sort()
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Sort();
}
}
/// <summary>
/// <inheritdoc cref="List{T}.Sort(Comparison{T})"/>
/// </summary>
/// <param name="comparison"></param>
public void Sort(Comparison<T> comparison)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Sort(comparison);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.Sort(IComparer{T})"/>
/// </summary>
/// <param name="comparer"></param>
public void Sort(IComparer<T> comparer)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Sort(comparer);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.Sort(int, int, IComparer{T})"/>
/// </summary>
/// <param name="index"></param>
/// <param name="count"></param>
/// <param name="comparer"></param>
public void Sort(int index, int count, IComparer<T> comparer)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Sort(index, count, comparer);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.ToArray"/>
/// </summary>
/// <returns></returns>
public T[] ToArray()
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.ToArray();
}
}
/// <summary>
/// <inheritdoc cref="List{T}.TrimExcess"/>
/// </summary>
public void TrimExcess()
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.TrimExcess();
}
}
/// <summary>
/// <inheritdoc cref="List{T}.TrueForAll(Predicate{T})"/>
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
public bool TrueForAll(Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.TrueForAll(match);
}
}
}

View File

@@ -11,7 +11,6 @@
#endregion
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Threading;
@@ -473,16 +472,6 @@ namespace ThingsGateway.Core.Extension
/// <returns></returns>
public static async Task ForeachAsync<T>(this IEnumerable<T> source, Func<T, Task> action, int maxParallelCount, CancellationToken cancellationToken = default)
{
if (Debugger.IsAttached)
{
foreach (var item in source)
{
await action(item);
}
return;
}
var list = new List<Task>();
foreach (var item in source)
{
@@ -512,13 +501,7 @@ namespace ThingsGateway.Core.Extension
/// <returns></returns>
public static Task ForeachAsync<T>(this IEnumerable<T> source, Func<T, Task> action, CancellationToken cancellationToken = default)
{
if (source is ICollection<T> collection)
{
return ForeachAsync(collection, action, collection.Count, cancellationToken);
}
var list = source.ToList();
return ForeachAsync(list, action, list.Count, cancellationToken);
return ForeachAsync(source, action, source.Count(), cancellationToken);
}
/// <summary>
@@ -621,16 +604,7 @@ namespace ThingsGateway.Core.Extension
public static async Task ForAsync<T>(this IEnumerable<T> source, Func<T, int, Task> selector, int maxParallelCount, CancellationToken cancellationToken = default)
{
int index = 0;
if (Debugger.IsAttached)
{
foreach (var item in source)
{
await selector(item, index);
index++;
}
return;
}
var list = new List<Task>();
foreach (var item in source)

View File

@@ -172,7 +172,7 @@ public class OperResult : IRequestInfo, IOperResult
/// </summary>
public string Exception { get; set; }
/// <inheritdoc/>
public bool IsSuccess => ResultCode.HasFlag(ResultCode.Success);
public bool IsSuccess => ResultCode == ResultCode.Success;
/// <inheritdoc/>
public string Message { get; set; }
/// <inheritdoc/>

View File

@@ -10,6 +10,8 @@
//------------------------------------------------------------------------------
#endregion
using System.Collections.Concurrent;
using ThingsGateway.Core;
namespace ThingsGateway.Web.Foundation;
@@ -73,7 +75,7 @@ public class MemoryVariable : BaseEntity
/// 变量额外属性Json通常使用为上传设备,List属性
/// </summary>
[SugarColumn(IsJson = true, ColumnName = "VariablePropertys", ColumnDescription = "变量属性Json", IsNullable = true)]
public Dictionary<long, List<DependencyProperty>> VariablePropertys { get; set; } = new();
public ConcurrentDictionary<long, List<DependencyProperty>> VariablePropertys { get; set; } = new();

View File

@@ -15,6 +15,8 @@ using System.Linq;
using System.Reflection;
using ThingsGateway.Core;
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Web.Foundation;
/// <summary>
/// 动态类型扩展
@@ -31,19 +33,18 @@ public static class ExpandoObjectHelpers
public static T ConvertToEntity<T>(this ExpandoObject expandoObject, bool filter) where T : new()
{
var entity = new T();
var properties = typeof(T).GetAllProps().Where(a => !filter || a.GetCustomAttribute<ExcelAttribute>() != null);
var properties = typeof(T).GetAllProps().Where(a => !filter || a.GetCustomAttribute<ExcelAttribute>() != null).ToDictionary(a => a.FindDisplayAttribute());
foreach (var keyValuePair in (IDictionary<string, object>)expandoObject)
expandoObject.ForEach(keyValuePair =>
{
var property = properties.FirstOrDefault(p => p.FindDisplayAttribute() == keyValuePair.Key);
if (property != null)
if (properties.TryGetValue(keyValuePair.Key, out var property))
{
var value = keyValuePair.Value;
var objValue = property.ObjToTypeValue(value?.ToString() ?? "");
property.SetValue(entity, objValue);
}
}
});
return entity;
}

View File

@@ -28,7 +28,7 @@ public static class ParallelHelpers
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <param name="body"></param>
public static void ParallelForEach<T>(this IEnumerable<T> source, Action<T> body) where T : class
public static void ParallelForEach<T>(this IEnumerable<T> source, Action<T> body)
{
Parallel.ForEach(source, _options, variable =>
{
@@ -36,4 +36,16 @@ public static class ParallelHelpers
});
}
/// <summary>
/// 执行<see cref="Parallel.ForEach{TSource}(IEnumerable{TSource}, Action{TSource})"/>
/// </summary>
public static void ParallelForEach<T>(this IEnumerable<T> source, Action<T> body, int parallelCount)
{
var options = new ParallelOptions();
options.MaxDegreeOfParallelism = parallelCount / 2 == 0 ? 1 : parallelCount;
Parallel.ForEach(source, options, variable =>
{
body(variable);
});
}
}

View File

@@ -16,13 +16,14 @@ using Microsoft.AspNetCore.Components.Forms;
using MiniExcelLibs;
using System.Collections.Concurrent;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Reflection;
using ThingsGateway.Core;
using ThingsGateway.Core.Extension;
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Web.Foundation;
@@ -234,29 +235,27 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS
if (devId == 0)
{
var devices = GetCacheList().Where(a => a.Enable).ToList();
var runtime = devices.Adapt<List<CollectDeviceRunTime>>();
var runtime = devices.Adapt<List<CollectDeviceRunTime>>().ToDictionary(a => a.Id);
using var serviceScope = _scopeFactory.CreateScope();
var variableService = serviceScope.ServiceProvider.GetService<IVariableService>();
var collectVariableRunTimes = await variableService.GetDeviceVariableRuntimeAsync();
await runtime.ForeachAsync(device =>
{
var pluginName = _driverPluginService.GetNameById(device.PluginId);
device.PluginName = pluginName;
device.DeviceVariableRunTimes = collectVariableRunTimes.Where(a => a.DeviceId == device.Id).ToList();
return Task.CompletedTask;
});
ConcurrentDictionary<long, DriverPlugin> driverPlugins = new(_driverPluginService.GetCacheList().ToDictionary(a => a.Id));
runtime.Values.ParallelForEach(device =>
{
driverPlugins.TryGetValue(device.PluginId, out var driverPlugin);
device.PluginName = driverPlugin?.AssembleName;
device.DeviceVariableRunTimes = collectVariableRunTimes.Where(a => a.DeviceId == device.Id).ToList();
});
await collectVariableRunTimes.ForeachAsync(variable =>
{
var device = runtime.FirstOrDefault(a => a.Id == variable.DeviceId);
if (device != null)
{
variable.CollectDeviceRunTime = device;
variable.DeviceName = device.Name;
}
return Task.CompletedTask;
});
return runtime;
collectVariableRunTimes.ParallelForEach(variable =>
{
if (runtime.TryGetValue(variable.DeviceId, out var device))
{
variable.CollectDeviceRunTime = device;
variable.DeviceName = device.Name;
}
});
return runtime.Values.ToList();
}
else
{
@@ -270,12 +269,11 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS
runtime.PluginName = pluginName;
runtime.DeviceVariableRunTimes = collectVariableRunTimes;
await collectVariableRunTimes.ForeachAsync(variable =>
{
variable.CollectDeviceRunTime = runtime;
variable.DeviceName = runtime.Name;
return Task.CompletedTask;
});
collectVariableRunTimes.ParallelForEach(variable =>
{
variable.CollectDeviceRunTime = runtime;
variable.DeviceName = runtime.Name;
});
return new() { runtime };
}
@@ -291,12 +289,13 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS
devDatas ??= GetCacheList();
//总数据
Dictionary<string, object> sheets = new Dictionary<string, object>();
Dictionary<string, object> sheets = new();
//设备页
List<Dictionary<string, object>> devExports = new();
//设备附加属性转成Dict<表名,List<Dict<列名,列数据>>>的形式
Dictionary<string, List<Dictionary<string, object>>> devicePropertys = new();
var driverPluginDicts = _driverPluginService.GetCacheList().ToDictionary(a => a.Id);
var deviceDicts = devDatas.ToDictionary(a => a.Id);
foreach (var devData in devDatas)
{
#region sheet
@@ -310,10 +309,13 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS
//数据源增加
devExport.Add(desc ?? item.Name, item.GetValue(devData)?.ToString());
}
driverPluginDicts.TryGetValue(devData.PluginId, out var driverPlugin);
deviceDicts.TryGetValue(devData.RedundantDeviceId, out var redundantDevice);
//设备实体没有包含插件名称,手动插入
devExport.Add(ExportHelpers.PluginName, _driverPluginService.GetNameById(devData.PluginId));
devExport.Add(ExportHelpers.PluginName, driverPlugin.AssembleName);
//设备实体没有包含冗余设备名称,手动插入
devExport.Add(ExportHelpers.RedundantDeviceName, GetNameById(devData.RedundantDeviceId));
devExport.Add(ExportHelpers.RedundantDeviceName, redundantDevice?.Name);
//添加完整设备信息
devExports.Add(devExport);
@@ -323,7 +325,7 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS
#region sheet
//插件属性
//单个设备的行数据
Dictionary<string, object> driverInfo = new Dictionary<string, object>();
Dictionary<string, object> driverInfo = new();
//没有包含设备名称,手动插入
if (devData.DevicePropertys.Count > 0)
{
@@ -336,7 +338,7 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS
}
//插件名称去除首部ThingsGateway.作为表名
var pluginName = _driverPluginService.GetNameById(devData.PluginId).Replace(ExportHelpers.PluginLeftName, "");
var pluginName = driverPlugin.AssembleName.Replace(ExportHelpers.PluginLeftName, "");
if (devicePropertys.ContainsKey(pluginName))
{
if (driverInfo.Count > 0)
@@ -372,6 +374,8 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS
using var stream = file.OpenReadStream(512000000);
await stream.CopyToAsync(fs);
var sheetNames = MiniExcel.GetSheetNames(fs);
var deviceDicts = GetCacheList().ToDictionary(a => a.Name);
var pluginDicts = _driverPluginService.GetCacheList().ToDictionary(a => a.AssembleName);
//导入检验结果
Dictionary<string, ImportPreviewOutputBase> ImportPreviews = new();
@@ -380,7 +384,7 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS
foreach (var sheetName in sheetNames)
{
//单页数据
var rows = (await fs.QueryAsync(useHeaderRow: true, sheetName: sheetName)).Cast<IDictionary<string, object>>();
var rows = fs.Query(useHeaderRow: true, sheetName: sheetName).Cast<IDictionary<string, object>>();
#region sheet
if (sheetName == ExportHelpers.CollectDeviceSheetName)
{
@@ -388,55 +392,57 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS
ImportPreviewOutput<CollectDevice> importPreviewOutput = new();
ImportPreviews.Add(sheetName, importPreviewOutput);
deviceImportPreview = importPreviewOutput;
List<CollectDevice> devices = new();
rows.ForEach(item =>
{
try
{
var device = ((ExpandoObject)item).ConvertToEntity<CollectDevice>(true);
//var hasDup = rows.HasDuplicateElements<DeviceVariable>(nameof(UploadDevice.Name), device.Name);
//var hasName = GetIdByName(device.Name) > 0;
//if (hasDup || hasName)
//{
// importPreviewOutput.HasError = true;
// importPreviewOutput.Results.Add((false, "名称重复"));
// return Task.CompletedTask;
//}
#region
//转化插件名称
var hasPlugin = item.TryGetValue(ExportHelpers.PluginName, out var pluginObj);
List<CollectDevice> devices = new List<CollectDevice>();
await rows.ForeachAsync(item =>
{
try
{
if (pluginObj == null || !pluginDicts.TryGetValue(pluginObj.ToString(), out var plugin))
{
//找不到对应的插件
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, $"{ExportHelpers.PluginName}不存在"));
return;
}
//转化冗余设备名称
var hasRedundant = item.TryGetValue(ExportHelpers.PluginName, out var redundantObj);
var device = ((ExpandoObject)item).ConvertToEntity<CollectDevice>(true);
//var hasDup = rows.HasDuplicateElements<DeviceVariable>(nameof(UploadDevice.Name), device.Name);
//var hasName = GetIdByName(device.Name) > 0;
//if (hasDup || hasName)
//{
// importPreviewOutput.HasError = true;
// importPreviewOutput.Results.Add((false, "名称重复"));
// return Task.CompletedTask;
//}
#region
//转化插件名称
var pluginName = item.FirstOrDefault(a => a.Key == ExportHelpers.PluginName).Value;
if (_driverPluginService.GetIdByName(pluginName?.ToString()) == null)
{
//找不到对应的插件
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, $"{ExportHelpers.PluginName}不存在"));
return Task.CompletedTask;
}
//转化冗余设备名称
var redundantDeviceName = item.FirstOrDefault(a => a.Key == ExportHelpers.RedundantDeviceName).Value;
#endregion
//插件ID、设备ID、冗余设备ID都需要手动补录
device.PluginId = plugin.Id;
if (hasRedundant && deviceDicts.TryGetValue(redundantObj.ToString(), out var rendundantDevice))
{
device.RedundantDeviceId = rendundantDevice.Id;
}
device.Id = deviceDicts.TryGetValue(device.Name, out var collectDevice) ? collectDevice.Id : YitIdHelper.NextId();
#endregion
//插件ID、设备ID、冗余设备ID都需要手动补录
device.PluginId = _driverPluginService.GetIdByName(pluginName.ToString()).ToLong();
device.RedundantDeviceId = GetIdByName(redundantDeviceName?.ToString()).ToLong();
device.Id = this.GetIdByName(device.Name) ?? YitIdHelper.NextId();
devices.Add(device);
importPreviewOutput.Results.Add((row++, true, "成功"));
return;
}
catch (Exception ex)
{
devices.Add(device);
importPreviewOutput.Results.Add((row++, true, "成功"));
return Task.CompletedTask;
}
catch (Exception ex)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, ex.Message));
return Task.CompletedTask;
}
});
importPreviewOutput.Data = devices;
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, ex.Message));
return;
}
});
importPreviewOutput.Data = devices.ToDictionary(a => a.Name);
}
#endregion
@@ -459,49 +465,43 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS
using var serviceScope = _scopeFactory.CreateScope();
var pluginSingletonService = serviceScope.ServiceProvider.GetService<PluginSingletonService>();
var driver = (DriverBase)pluginSingletonService.GetDriver(YitIdHelper.NextId(), driverPlugin);
var propertys = driver.DriverPropertys.GetType().GetAllProps().Where(a => a.GetCustomAttribute<DevicePropertyAttribute>() != null);
await rows.ForeachAsync(item =>
{
try
{
var propertys = driver.DriverPropertys.GetType().GetAllProps()
.Where(a => a.GetCustomAttribute<DevicePropertyAttribute>() != null)
.ToDictionary(a => a.FindDisplayAttribute(a => a.GetCustomAttribute<DevicePropertyAttribute>()?.Description));
rows.ForEach(item =>
{
try
{
List<DependencyProperty> devices = new List<DependencyProperty>();
foreach (var item1 in item)
{
var propertyInfo = propertys.FirstOrDefault(p => p.FindDisplayAttribute(a => a.GetCustomAttribute<DevicePropertyAttribute>()?.Description) == item1.Key);
if (propertyInfo == null)
{
//不存在时不报错
}
else
{
devices.Add(new()
{
PropertyName = propertyInfo.Name,
Description = item1.Key.ToString(),
Value = item1.Value?.ToString()
});
}
List<DependencyProperty> devices = new();
foreach (var keyValuePair in item)
{
if (propertys.TryGetValue(keyValuePair.Key, out var propertyInfo))
{
devices.Add(new()
{
PropertyName = propertyInfo.Name,
Description = keyValuePair.Key.ToString(),
Value = keyValuePair.Value?.ToString()
});
}
}
//转化插件名称
var value = item.FirstOrDefault(a => a.Key == ExportHelpers.DeviceName);
if (deviceImportPreview.Data?.Any(it => it.Name == value.Value.ToString()) == true)
{
var deviceId = this.GetIdByName(value.Value.ToString()) ?? deviceImportPreview.Data.FirstOrDefault(it => it.Name == value.Value.ToString()).Id;
deviceImportPreview.Data.FirstOrDefault(a => a.Id == deviceId).DevicePropertys = devices;
}
importPreviewOutput.Data.Add(string.Empty);
importPreviewOutput.Results.Add((row++, true, "成功"));
return Task.CompletedTask;
}
catch (Exception ex)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, ex.Message));
return Task.CompletedTask;
}
});
}
//转化插件名称
var value = item[ExportHelpers.DeviceName];
deviceImportPreview.Data[value.ToString()].DevicePropertys = devices;
importPreviewOutput.Results.Add((row++, true, "成功"));
return;
}
catch (Exception ex)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, ex.Message));
return;
}
});
}
}
@@ -521,7 +521,7 @@ public class CollectDeviceService : DbRepository<CollectDevice>, ICollectDeviceS
if (item.Key == ExportHelpers.CollectDeviceSheetName)
{
var collectDeviceImports = ((ImportPreviewOutput<CollectDevice>)item.Value).Data;
collectDevices = collectDeviceImports.Adapt<List<CollectDevice>>();
collectDevices = collectDeviceImports.Values.Adapt<List<CollectDevice>>();
break;
}
}

View File

@@ -16,13 +16,14 @@ using Microsoft.AspNetCore.Components.Forms;
using MiniExcelLibs;
using System.Collections.Concurrent;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Reflection;
using ThingsGateway.Core;
using ThingsGateway.Core.Extension;
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Web.Foundation;
@@ -162,30 +163,31 @@ public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceServ
public List<UploadDevice> GetCacheList()
{
//先从Cache拿
var collectDevice = _sysCacheService.Get<List<UploadDevice>>(ThingsGatewayCacheConst.Cache_UploadDevice, "");
if (collectDevice == null)
var uploadDevice = _sysCacheService.Get<List<UploadDevice>>(ThingsGatewayCacheConst.Cache_UploadDevice, "");
if (uploadDevice == null)
{
collectDevice = Context.Queryable<UploadDevice>().ToList();
if (collectDevice != null)
uploadDevice = Context.Queryable<UploadDevice>().ToList();
if (uploadDevice != null)
{
//插入Cache
_sysCacheService.Set(ThingsGatewayCacheConst.Cache_UploadDevice, "", collectDevice);
_sysCacheService.Set(ThingsGatewayCacheConst.Cache_UploadDevice, "", uploadDevice);
}
}
return collectDevice;
return uploadDevice;
}
/// <inheritdoc/>
public List<UploadDeviceRunTime> GetUploadDeviceRuntime(long devId = 0)
{
ConcurrentDictionary<long, DriverPlugin> driverPlugins = new(_driverPluginService.GetCacheList().ToDictionary(a => a.Id));
if (devId == 0)
{
var devices = GetCacheList().Where(a => a.Enable).ToList();
var runtime = devices.Adapt<List<UploadDeviceRunTime>>();
foreach (var device in runtime)
{
var pluginName = _driverPluginService.GetNameById(device.PluginId);
device.PluginName = pluginName;
driverPlugins.TryGetValue(device.PluginId, out var driverPlugin);
device.PluginName = driverPlugin?.AssembleName;
}
return runtime;
}
@@ -196,8 +198,8 @@ public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceServ
var runtime = devices.Adapt<List<UploadDeviceRunTime>>();
foreach (var device in runtime)
{
var pluginName = _driverPluginService.GetNameById(device.PluginId);
device.PluginName = pluginName;
driverPlugins.TryGetValue(device.PluginId, out var driverPlugin);
device.PluginName = driverPlugin?.AssembleName;
}
return runtime;
@@ -214,7 +216,7 @@ public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceServ
devDatas ??= GetCacheList();
//总数据
Dictionary<string, object> sheets = new Dictionary<string, object>();
Dictionary<string, object> sheets = new();
//设备页
List<Dictionary<string, object>> devExports = new();
//设备附加属性转成Dict<表名,List<Dict<列名,列数据>>>的形式
@@ -244,7 +246,7 @@ public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceServ
#region sheet
//插件属性
//单个设备的行数据
Dictionary<string, object> driverInfo = new Dictionary<string, object>();
Dictionary<string, object> driverInfo = new();
//没有包含设备名称,手动插入
if (devData.DevicePropertys.Count > 0)
{
@@ -293,6 +295,8 @@ public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceServ
using var stream = file.OpenReadStream(512000000);
await stream.CopyToAsync(fs);
var sheetNames = MiniExcel.GetSheetNames(fs);
var deviceDicts = GetCacheList().ToDictionary(a => a.Name);
var pluginDicts = _driverPluginService.GetCacheList().ToDictionary(a => a.AssembleName);
//导入检验结果
Dictionary<string, ImportPreviewOutputBase> ImportPreviews = new();
@@ -301,7 +305,7 @@ public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceServ
foreach (var sheetName in sheetNames)
{
//单页数据
var rows = (await fs.QueryAsync(useHeaderRow: true, sheetName: sheetName)).Cast<IDictionary<string, object>>();
var rows = (fs.Query(useHeaderRow: true, sheetName: sheetName)).Cast<IDictionary<string, object>>();
#region sheet
if (sheetName == ExportHelpers.UploadDeviceSheetName)
{
@@ -310,47 +314,48 @@ public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceServ
ImportPreviews.Add(sheetName, importPreviewOutput);
deviceImportPreview = importPreviewOutput;
List<UploadDevice> devices = new List<UploadDevice>();
await rows.ForeachAsync(item =>
{
try
{
var device = ((ExpandoObject)item).ConvertToEntity<UploadDevice>(true);
//var hasDup = rows.HasDuplicateElements<DeviceVariable>(nameof(UploadDevice.Name), device.Name);
//var hasName = GetIdByName(device.Name) > 0;
//if (hasDup || hasName)
//{
// importPreviewOutput.HasError = true;
// importPreviewOutput.Results.Add((false, "名称重复"));
// return Task.CompletedTask;
//}
#region
//转化插件名称
var pluginName = item.FirstOrDefault(a => a.Key == ExportHelpers.PluginName).Value;
if (_driverPluginService.GetIdByName(pluginName?.ToString()) == null)
{
//找不到对应的插件
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, $"{ExportHelpers.PluginName}不存在"));
return Task.CompletedTask;
}
#endregion
//插件ID、设备ID都需要手动补录
device.PluginId = _driverPluginService.GetIdByName(pluginName?.ToString()).ToLong();
device.Id = this.GetIdByName(device.Name) ?? YitIdHelper.NextId();
List<UploadDevice> devices = new();
rows.ForEach(item =>
{
try
{
var device = ((ExpandoObject)item).ConvertToEntity<UploadDevice>(true);
//var hasDup = rows.HasDuplicateElements<DeviceVariable>(nameof(UploadDevice.Name), device.Name);
//var hasName = GetIdByName(device.Name) > 0;
//if (hasDup || hasName)
//{
// importPreviewOutput.HasError = true;
// importPreviewOutput.Results.Add((false, "名称重复"));
// return Task.CompletedTask;
//}
#region
//转化插件名称
var hasPlugin = item.TryGetValue(ExportHelpers.PluginName, out var pluginObj);
devices.Add(device);
importPreviewOutput.Results.Add((row++, true, "成功"));
return Task.CompletedTask;
}
catch (Exception ex)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, ex.Message));
return Task.CompletedTask;
}
});
importPreviewOutput.Data = devices;
if (pluginObj == null || !pluginDicts.TryGetValue(pluginObj.ToString(), out var plugin))
{
//找不到对应的插件
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, $"{ExportHelpers.PluginName}不存在"));
return;
}
#endregion
//插件ID、设备ID都需要手动补录
device.PluginId = plugin.Id;
device.Id = deviceDicts.TryGetValue(device.Name, out var uploadDevice) ? uploadDevice.Id : YitIdHelper.NextId();
devices.Add(device);
importPreviewOutput.Results.Add((row++, true, "成功"));
return;
}
catch (Exception ex)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, ex.Message));
return;
}
});
importPreviewOutput.Data = devices.ToDictionary(a => a.Name);
}
#endregion
@@ -374,51 +379,43 @@ public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceServ
using var serviceScope = _scopeFactory.CreateScope();
var pluginSingletonService = serviceScope.ServiceProvider.GetService<PluginSingletonService>();
var driver = (DriverBase)pluginSingletonService.GetDriver(YitIdHelper.NextId(), driverPlugin);
var propertys = driver.DriverPropertys.GetType().GetAllProps().Where(a => a.GetCustomAttribute<DevicePropertyAttribute>() != null);
await rows.ForeachAsync(item =>
{
try
var propertys = driver.DriverPropertys.GetType().GetAllProps()
.Where(a => a.GetCustomAttribute<DevicePropertyAttribute>() != null)
.ToDictionary(a => a.FindDisplayAttribute(a => a.GetCustomAttribute<DevicePropertyAttribute>()?.Description));
rows.ForEach(item =>
{
List<DependencyProperty> devices = new List<DependencyProperty>();
foreach (var item1 in item)
try
{
var propertyInfo = propertys.FirstOrDefault(p => p.FindDisplayAttribute(a => a.GetCustomAttribute<DevicePropertyAttribute>()?.Description) == item1.Key);
if (propertyInfo == null)
List<DependencyProperty> devices = new();
foreach (var keyValuePair in item)
{
//不存在时不报错
}
else
{
devices.Add(new()
if (propertys.TryGetValue(keyValuePair.Key, out var propertyInfo))
{
PropertyName = propertyInfo.Name,
Description = item1.Key.ToString(),
Value = item1.Value?.ToString()
});
devices.Add(new()
{
PropertyName = propertyInfo.Name,
Description = keyValuePair.Key.ToString(),
Value = keyValuePair.Value?.ToString()
});
}
}
//转化设备名称
var value = item[ExportHelpers.DeviceName];
deviceImportPreview.Data[value.ToString()].DevicePropertys = devices;
importPreviewOutput.Results.Add((row++, true, "成功"));
return;
}
//转化设备名称
var deviceName = item.FirstOrDefault(a => a.Key == ExportHelpers.DeviceName).Value;
if (deviceImportPreview.Data?.Any(it => it.Name == deviceName.ToString()) == true)
catch (Exception ex)
{
var deviceId = this.GetIdByName(deviceName.ToString()) ?? deviceImportPreview.Data.FirstOrDefault(it => it.Name == deviceName.ToString()).Id;
deviceImportPreview.Data.FirstOrDefault(a => a.Id == deviceId).DevicePropertys = devices;
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, ex.Message));
return;
}
importPreviewOutput.Data.Add(string.Empty);
importPreviewOutput.Results.Add((row++, true, "成功"));
return Task.CompletedTask;
}
catch (Exception ex)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, ex.Message));
return Task.CompletedTask;
}
});
});
}
}
@@ -432,18 +429,18 @@ public class UploadDeviceService : DbRepository<UploadDevice>, IUploadDeviceServ
[OperDesc("导入上传设备表", IsRecordPar = false)]
public async Task ImportAsync(Dictionary<string, ImportPreviewOutputBase> input)
{
var collectDevices = new List<UploadDevice>();
var uploadDevices = new List<UploadDevice>();
foreach (var item in input)
{
if (item.Key == ExportHelpers.UploadDeviceSheetName)
{
var collectDeviceImports = ((ImportPreviewOutput<UploadDevice>)item.Value).Data;
collectDevices = collectDeviceImports.Adapt<List<UploadDevice>>();
var uploadDeviceImports = ((ImportPreviewOutput<UploadDevice>)item.Value).Data;
uploadDevices = uploadDeviceImports.Values.Adapt<List<UploadDevice>>();
break;
}
}
await Context.Storageable(collectDevices).ExecuteCommandAsync();
_sysCacheService.Remove(ThingsGatewayCacheConst.Cache_CollectDevice, "");//cache删除
await Context.Storageable(uploadDevices).ExecuteCommandAsync();
_sysCacheService.Remove(ThingsGatewayCacheConst.Cache_UploadDevice, "");//cache删除
}

View File

@@ -70,7 +70,7 @@ public interface IVariableService : ITransient
/// <summary>
/// 根据名称获取ID
/// </summary>
long GetIdByName(string name, bool onlyCache = true);
long GetIdByName(string name);
/// <summary>
/// 获取中间变量运行态
/// </summary>
@@ -80,7 +80,7 @@ public interface IVariableService : ITransient
/// <summary>
/// 根据ID获取名称
/// </summary>
string GetNameById(long id, bool onlyCache = true);
string GetNameById(long id);
/// <summary>
/// 导入
/// </summary>

View File

@@ -18,13 +18,14 @@ using Microsoft.AspNetCore.Components.Forms;
using MiniExcelLibs;
using MiniExcelLibs.OpenXml;
using System.Collections.Concurrent;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using ThingsGateway.Core;
using ThingsGateway.Core.Extension;
using TouchSocket.Core;
@@ -66,11 +67,11 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService
}
/// <inheritdoc/>
public long GetIdByName(string name, bool onlyCache = false)
public long GetIdByName(string name)
{
//先从Cache拿
var id = _sysCacheService.Get<long>(ThingsGatewayCacheConst.Cache_DeviceVariableName, name);
if (id == 0 && !onlyCache)
if (id == 0)
{
//单查获取对应ID
id = Context.Queryable<DeviceVariable>().Where(it => it.Name == name).Select(it => it.Id).First();
@@ -83,11 +84,11 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService
return id;
}
/// <inheritdoc/>
public string GetNameById(long Id, bool onlyCache = true)
public string GetNameById(long Id)
{
//先从Cache拿
var name = _sysCacheService.Get<string>(ThingsGatewayCacheConst.Cache_DeviceVariableId, Id.ToString());
if (name.IsNullOrEmpty() && !onlyCache)
if (name.IsNullOrEmpty())
{
//单查获取用户账号对应ID
name = Context.Queryable<DeviceVariable>().Where(it => it.Id == Id).Select(it => it.Name).First();
@@ -287,41 +288,77 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService
/// <inheritdoc/>
[OperDesc("导出变量表", IsRecordPar = false)]
public async Task<MemoryStream> MemoryVariableExportFileAsync(List<MemoryVariable> devDatas = null)
public async Task<MemoryStream> MemoryVariableExportFileAsync(List<MemoryVariable> deviceVariables = null)
{
devDatas ??= (await GetListAsync(a => a.IsMemoryVariable == true)).Adapt<List<MemoryVariable>>();
deviceVariables ??= (await GetListAsync(a => a.IsMemoryVariable == true)).Adapt<List<MemoryVariable>>();
//总数据
Dictionary<string, object> sheets = new Dictionary<string, object>();
//变量页
List<Dictionary<string, object>> devExports = new();
ConcurrentList<Dictionary<string, object>> devExports = new();
//变量附加属性转成Dict<表名,List<Dict<列名,列数据>>>的形式
Dictionary<string, List<Dictionary<string, object>>> devicePropertys = new();
await devDatas.ForeachAsync(devData =>
ConcurrentDictionary<string, List<Dictionary<string, object>>> devicePropertys = new();
var upDeviceDicts = _uploadDeviceService.GetCacheList().ToDictionary(a => a.Id);
var collectDeviceDicts = _collectDeviceService.GetCacheList().ToDictionary(a => a.Id);
var driverPluginDicts = _driverPluginService.GetCacheList().ToDictionary(a => a.Id);
deviceVariables.ParallelForEach(devData =>
{
#region sheet
//变量页
var data = devData.GetType().GetAllProps().Where(a => a.GetCustomAttribute<ExcelAttribute>() != null);
Dictionary<string, object> devExport = new();
Dictionary<string, object> variableExport = new();
foreach (var item in data)
{
//描述
var desc = ObjectExtensions.FindDisplayAttribute(item);
//数据源增加
devExport.Add(desc ?? item.Name, item.GetValue(devData)?.ToString());
variableExport.Add(desc ?? item.Name, item.GetValue(devData)?.ToString());
}
//添加完整变量信息
devExports.Add(devExport);
devExports.Add(variableExport);
#endregion
#region
foreach (var item in devData.VariablePropertys ?? new())
{
//插件属性
//单个设备的行数据
Dictionary<string, object> driverInfo = new Dictionary<string, object>();
var has = upDeviceDicts.TryGetValue(item.Key, out var uploadDevice);
if (!has)
continue;
driverInfo.Add(ExportHelpers.UploadDeviceSheetName, uploadDevice?.Name);
//没有包含变量名称,手动插入
driverInfo.Add(ExportHelpers.DeviceVariableSheetName, devData.Name);
foreach (var item1 in item.Value)
{
//添加对应属性数据
driverInfo.Add(item1.Description, item1.Value);
}
if (uploadDevice != null)
{
//插件名称去除首部ThingsGateway.作为表名
var pluginName = driverPluginDicts[uploadDevice.PluginId].AssembleName.Replace(ExportHelpers.PluginLeftName, "");
if (devicePropertys.ContainsKey(pluginName))
{
devicePropertys[pluginName].Add(driverInfo);
}
else
{
devicePropertys.TryAdd(pluginName, new() { driverInfo });
}
}
}
#endregion
return Task.CompletedTask;
});
//添加设备
//添加变量
sheets.Add(ExportHelpers.DeviceVariableSheetName, devExports);
//添加插件属性页
foreach (var item in devicePropertys)
@@ -336,76 +373,79 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService
/// <inheritdoc/>
[OperDesc("导出变量表", IsRecordPar = false)]
public async Task<MemoryStream> ExportFileAsync(List<DeviceVariable> devDatas = null)
public async Task<MemoryStream> ExportFileAsync(List<DeviceVariable> deviceVariables = null)
{
devDatas ??= await GetListAsync(a => a.IsMemoryVariable != true || a.IsMemoryVariable == null);
deviceVariables ??= await GetListAsync(a => a.IsMemoryVariable != true || a.IsMemoryVariable == null);
//总数据
Dictionary<string, object> sheets = new Dictionary<string, object>();
//变量页
List<Dictionary<string, object>> devExports = new();
ConcurrentList<Dictionary<string, object>> devExports = new();
//变量附加属性转成Dict<表名,List<Dict<列名,列数据>>>的形式
Dictionary<string, List<Dictionary<string, object>>> devicePropertys = new();
await devDatas.ForeachAsync(devData =>
{
#region sheet
//变量页
var data = devData.GetType().GetAllProps().Where(a => a.GetCustomAttribute<ExcelAttribute>() != null);
Dictionary<string, object> devExport = new();
//变量实体没有包含设备名称,手动插入
devExport.Add(ExportHelpers.DeviceName, _collectDeviceService.GetNameById(devData.DeviceId));
ConcurrentDictionary<string, List<Dictionary<string, object>>> devicePropertys = new();
var upDeviceDicts = _uploadDeviceService.GetCacheList().ToDictionary(a => a.Id);
var collectDeviceDicts = _collectDeviceService.GetCacheList().ToDictionary(a => a.Id);
var driverPluginDicts = _driverPluginService.GetCacheList().ToDictionary(a => a.Id);
deviceVariables.ParallelForEach(devData =>
{
#region sheet
//变量
var data = devData.GetType().GetAllProps().Where(a => a.GetCustomAttribute<ExcelAttribute>() != null);
Dictionary<string, object> variableExport = new();
//变量实体没有包含设备名称,手动插入
variableExport.Add(ExportHelpers.DeviceName, collectDeviceDicts[devData.DeviceId]);
foreach (var item in data)
{
//描述
var desc = ObjectExtensions.FindDisplayAttribute(item);
//数据源增加
devExport.Add(desc ?? item.Name, item.GetValue(devData)?.ToString());
}
foreach (var item in data)
{
//描述
var desc = ObjectExtensions.FindDisplayAttribute(item);
//数据源增加
variableExport.Add(desc ?? item.Name, item.GetValue(devData)?.ToString());
}
//添加完整变量信息
devExports.Add(variableExport);
#endregion
#region
foreach (var item in devData.VariablePropertys ?? new())
{
//插件属性
//单个设备的行数据
Dictionary<string, object> driverInfo = new Dictionary<string, object>();
var has = upDeviceDicts.TryGetValue(item.Key, out var uploadDevice);
if (!has)
continue;
driverInfo.Add(ExportHelpers.UploadDeviceSheetName, uploadDevice?.Name);
//没有包含变量名称,手动插入
driverInfo.Add(ExportHelpers.DeviceVariableSheetName, devData.Name);
foreach (var item1 in item.Value)
{
//添加对应属性数据
driverInfo.Add(item1.Description, item1.Value);
}
if (uploadDevice != null)
{
//插件名称去除首部ThingsGateway.作为表名
var pluginName = driverPluginDicts[uploadDevice.PluginId].AssembleName.Replace(ExportHelpers.PluginLeftName, "");
if (devicePropertys.ContainsKey(pluginName))
{
devicePropertys[pluginName].Add(driverInfo);
}
else
{
devicePropertys.TryAdd(pluginName, new() { driverInfo });
}
}
//添加完整变量信息
devExports.Add(devExport);
}
#endregion
#endregion
#region
foreach (var item in devData.VariablePropertys ?? new())
{
//插件属性
//单个设备的行数据
Dictionary<string, object> driverInfo = new Dictionary<string, object>();
var uploadDevice = _uploadDeviceService.GetDeviceById(item.Key);
driverInfo.Add(ExportHelpers.UploadDeviceSheetName, uploadDevice?.Name);
//没有包含变量名称,手动插入
driverInfo.Add(ExportHelpers.DeviceVariableSheetName, devData.Name);
foreach (var item1 in item.Value)
{
//添加对应属性数据
driverInfo.Add(item1.Description, item1.Value);
}
});
if (uploadDevice != null)
{
//插件名称去除首部ThingsGateway.作为表名
var pluginName = _driverPluginService.GetNameById(uploadDevice.PluginId).Replace(ExportHelpers.PluginLeftName, "");
if (devicePropertys.ContainsKey(pluginName))
{
devicePropertys[pluginName].Add(driverInfo);
}
else
{
devicePropertys.Add(pluginName, new() { driverInfo });
}
}
}
#endregion
return Task.CompletedTask;
});
//添加设备页
//添加变量页
sheets.Add(ExportHelpers.DeviceVariableSheetName, devExports);
//添加插件属性页
foreach (var item in devicePropertys)
@@ -427,13 +467,14 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService
await stream.CopyToAsync(fs);
var sheetNames = MiniExcel.GetSheetNames(fs);
var deviceVariables = await GetListAsync();
foreach (var item in deviceVariables)
var dbVariables = await Context.Queryable<DeviceVariable>().Select(it => new { it.Id, it.Name }).ToListAsync();
foreach (var item in dbVariables)
{
_sysCacheService.Set(ThingsGatewayCacheConst.Cache_DeviceVariableName, item.Name, item.Id);
_sysCacheService.Set(ThingsGatewayCacheConst.Cache_DeviceVariableId, item.Id.ToString(), item.Name);
}
//转为字典,提高查找效率
var dbVariableDicts = dbVariables.ToDictionary(a => a.Name);
//导入检验结果
Dictionary<string, ImportPreviewOutputBase> ImportPreviews = new();
//设备页
@@ -451,125 +492,35 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService
ImportPreviews.Add(sheetName, importPreviewOutput);
deviceImportPreview = importPreviewOutput;
//线程安全
List<DeviceVariable> variables = new List<DeviceVariable>();
rows.ParallelForEach(item =>
{
try
{
var variable = ((ExpandoObject)item).ConvertToEntity<DeviceVariable>(true);
List<DeviceVariable> devices = new List<DeviceVariable>();
await rows.ForeachAsync(item =>
{
try
{
var device = ((ExpandoObject)item).ConvertToEntity<DeviceVariable>(true);
//var hasDup = rows.HasDuplicateElements<DeviceVariable>(nameof(DeviceVariable.Name), device.Name);
//var hasName = GetIdByName(device.Name) > 0;
//if (hasDup || hasName)
//{
// importPreviewOutput.HasError = true;
// importPreviewOutput.Results.Add((false, "名称重复"));
// return Task.CompletedTask;
//}
//变量ID都需要手动补录
variables.Add(variable);
variable.Id = dbVariableDicts.TryGetValue(variable.Name, out var dbvar1) ? dbvar1.Id : YitIdHelper.NextId();
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), true, "成功"));
}
catch (Exception ex)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), false, ex.Message));
}
});
//var hasDup = rows.HasDuplicateElements<DeviceVariable>(nameof(DeviceVariable.Name), device.Name);
//var hasName = GetIdByName(device.Name) > 0;
//if (hasDup || hasName)
//{
// importPreviewOutput.HasError = true;
// importPreviewOutput.Results.Add((false, "名称重复"));
// return Task.CompletedTask;
//}
//变量ID都需要手动补录
devices.Add(device);
device.Id = this.GetIdByName(device.Name, true) == 0 ? YitIdHelper.NextId() : this.GetIdByName(device.Name, true);
importPreviewOutput.Results.Add((row++, true, "成功"));
return Task.CompletedTask;
}
catch (Exception ex)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, ex.Message));
return Task.CompletedTask;
}
});
importPreviewOutput.Data = devices;
}
}
return ImportPreviews;
}
/// <inheritdoc/>
public async Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IBrowserFile file)
{
_fileService.ImportVerification(file);
using var fs = new MemoryStream();
using var stream = file.OpenReadStream(512000000);
await stream.CopyToAsync(fs);
var sheetNames = MiniExcel.GetSheetNames(fs);
var deviceVariables = await GetListAsync();
foreach (var item in deviceVariables)
{
_sysCacheService.Set(ThingsGatewayCacheConst.Cache_DeviceVariableName, item.Name, item.Id);
_sysCacheService.Set(ThingsGatewayCacheConst.Cache_DeviceVariableId, item.Id.ToString(), item.Name);
}
//导入检验结果
Dictionary<string, ImportPreviewOutputBase> ImportPreviews = new();
//设备页
ImportPreviewOutput<DeviceVariable> deviceImportPreview = new();
foreach (var sheetName in sheetNames)
{
//单页数据
var rows = fs.Query(useHeaderRow: true, sheetName: sheetName, configuration: new OpenXmlConfiguration { EnableSharedStringCache = false })
.Cast<IDictionary<string, object>>();
if (sheetName == ExportHelpers.DeviceVariableSheetName)
{
int row = 1;
ImportPreviewOutput<DeviceVariable> importPreviewOutput = new();
ImportPreviews.Add(sheetName, importPreviewOutput);
deviceImportPreview = importPreviewOutput;
List<DeviceVariable> devices = new List<DeviceVariable>();
await rows.ForeachAsync(item =>
{
try
{
var device = ((ExpandoObject)item).ConvertToEntity<DeviceVariable>(true);
//var hasDup = rows.HasDuplicateElements<DeviceVariable>(nameof(DeviceVariable.Name), device.Name);
//var hasName = GetIdByName(device.Name) > 0;
//if (hasDup || hasName)
//{
// importPreviewOutput.HasError = true;
// importPreviewOutput.Results.Add((false, "名称重复"));
// return Task.CompletedTask;
//}
//转化设备名称
var deviceName = item.FirstOrDefault(a => a.Key == ExportHelpers.DeviceName).Value;
if (_collectDeviceService.GetIdByName(deviceName?.ToString()) == null)
{
//找不到对应的设备
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, $"{deviceName}设备不存在"));
return Task.CompletedTask;
}
else
{
//变量ID和设备ID都需要手动补录
device.DeviceId = _collectDeviceService.GetIdByName(deviceName.ToString()).ToLong();
device.Id = this.GetIdByName(device.Name, true) == 0 ? YitIdHelper.NextId() : this.GetIdByName(device.Name, true);
}
devices.Add(device);
importPreviewOutput.Results.Add((row++, true, "成功"));
return Task.CompletedTask;
}
catch (Exception ex)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, ex.Message));
return Task.CompletedTask;
}
});
importPreviewOutput.Data = devices;
importPreviewOutput.Data = variables.OrderBy(a => a.Id).ToDictionary(a => a.Name);
}
else
@@ -587,7 +538,7 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService
if (pluginId == null)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, $"插件{newName}不存在"));
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), false, $"插件{newName}不存在"));
continue;
}
@@ -595,59 +546,255 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService
using var serviceScope = _scopeFactory.CreateScope();
var pluginSingletonService = serviceScope.ServiceProvider.GetService<PluginSingletonService>();
var driver = (UpLoadBase)pluginSingletonService.GetDriver(YitIdHelper.NextId(), driverPlugin);
var propertys = driver.VariablePropertys.GetType().GetAllProps().Where(a => a.GetCustomAttribute<VariablePropertyAttribute>() != null);
await rows.ForeachAsync(item =>
{
try
{
var propertys = driver.VariablePropertys.GetType().GetAllProps()
.Where(a => a.GetCustomAttribute<VariablePropertyAttribute>() != null)
.ToDictionary(a => a.FindDisplayAttribute(a => a.GetCustomAttribute<VariablePropertyAttribute>()?.Description));
List<DependencyProperty> devices = new List<DependencyProperty>();
foreach (var item1 in item)
var cacheUpdeviceDicts = _uploadDeviceService.GetCacheList().ToDictionary(a => a.Name);
rows.ParallelForEach(item =>
{
try
{
List<DependencyProperty> dependencyProperties = new List<DependencyProperty>();
foreach (var keyValuePair in item)
{
if (propertys.TryGetValue(keyValuePair.Key, out var propertyInfo))
{
var propertyInfo = propertys.FirstOrDefault(p => p.FindDisplayAttribute(a => a.GetCustomAttribute<VariablePropertyAttribute>()?.Description) == item1.Key);
if (propertyInfo == null)
dependencyProperties.Add(new()
{
//不存在时不报错
PropertyName = propertyInfo.Name,
Description = keyValuePair.Key.ToString(),
Value = keyValuePair.Value?.ToString()
});
}
}
//转化插件名称
item.TryGetValue(ExportHelpers.DeviceVariableSheetName, out var variableNameObj);
item.TryGetValue(ExportHelpers.UploadDeviceSheetName, out var uploadDevName);
var variableName = variableNameObj?.ToString();
if (uploadDevName != null)
{
cacheUpdeviceDicts.TryGetValue(uploadDevName.ToString(), out var uploadDevice);
var has = deviceImportPreview.Data.TryGetValue(variableName, out var deviceVariable);
if (has)
{
if (uploadDevice != null)
{
deviceVariable.VariablePropertys?.AddOrUpdate(uploadDevice.Id, a => dependencyProperties, (a, b) => dependencyProperties);
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), true, "成功"));
}
else
{
devices.Add(new()
{
PropertyName = propertyInfo.Name,
Description = item1.Key.ToString(),
Value = item1.Value?.ToString()
});
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), true, $"上传设备{uploadDevName}不存在"));
}
}
//转化插件名称
var variableName = item.FirstOrDefault(a => a.Key == ExportHelpers.DeviceVariableSheetName).Value?.ToString();
var uploadDevName = item.FirstOrDefault(a => a.Key == ExportHelpers.UploadDeviceSheetName).Value?.ToString();
var uploadDevice = _uploadDeviceService.GetCacheList().FirstOrDefault(a => a.Name == uploadDevName);
if (deviceImportPreview.Data?.Any(it => it.Name == variableName) == true && uploadDevice != null)
else
{
var id = this.GetIdByName(variableName, true);
var deviceId = id != 0 ? id : deviceImportPreview.Data.FirstOrDefault(it => it.Name == variableName).Id;
deviceImportPreview?.Data?.FirstOrDefault(a => a.Id == deviceId)?.VariablePropertys?.AddOrUpdate(uploadDevice.Id, devices);
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), true, $"上传设备{uploadDevName}不存在"));
}
importPreviewOutput.Data.Add(string.Empty);
importPreviewOutput.Results.Add((row++, true, "成功"));
return Task.CompletedTask;
}
catch (Exception ex)
else
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, ex.Message));
return Task.CompletedTask;
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), true, $"上传设备{uploadDevName}不存在"));
}
});
}
catch (Exception ex)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), false, ex.Message));
}
});
}
catch (Exception ex)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((row++, false, ex.Message));
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), false, ex.Message));
}
}
}
return ImportPreviews;
}
/// <inheritdoc/>
public async Task<Dictionary<string, ImportPreviewOutputBase>> PreviewAsync(IBrowserFile file)
{
_fileService.ImportVerification(file);
using var fs = new MemoryStream();
using var stream = file.OpenReadStream(512000000);
await stream.CopyToAsync(fs);
var sheetNames = MiniExcel.GetSheetNames(fs);
var dbVariables = await Context.Queryable<DeviceVariable>().Select(it => new { it.Id, it.Name }).ToListAsync();
foreach (var item in dbVariables)
{
_sysCacheService.Set(ThingsGatewayCacheConst.Cache_DeviceVariableName, item.Name, item.Id);
_sysCacheService.Set(ThingsGatewayCacheConst.Cache_DeviceVariableId, item.Id.ToString(), item.Name);
}
//转为字典,提高查找效率
var dbVariableDicts = dbVariables.ToDictionary(a => a.Name);
//检验结果
Dictionary<string, ImportPreviewOutputBase> ImportPreviews = new();
//设备页
ImportPreviewOutput<DeviceVariable> deviceImportPreview = new();
foreach (var sheetName in sheetNames)
{
//单页数据
var rows = fs.Query(useHeaderRow: true, sheetName: sheetName, configuration: new OpenXmlConfiguration { EnableSharedStringCache = false })
.Cast<IDictionary<string, object>>();
if (sheetName == ExportHelpers.DeviceVariableSheetName)
{
int row = 0;
ImportPreviewOutput<DeviceVariable> importPreviewOutput = new();
ImportPreviews.Add(sheetName, importPreviewOutput);
deviceImportPreview = importPreviewOutput;
var cacheDeviceDicts = _collectDeviceService.GetCacheList().ToDictionary(a => a.Name);
//线程安全
var variables = new ConcurrentList<DeviceVariable>();
//并行注意线程安全
rows.ParallelForEach(item =>
{
try
{
var variable = ((ExpandoObject)item).ConvertToEntity<DeviceVariable>(true);
//var hasDup = rows.HasDuplicateElements<DeviceVariable>(nameof(DeviceVariable.Name), device.Name);
//var hasName = GetIdByName(device.Name) > 0;
//if (hasDup || hasName)
//{
// importPreviewOutput.HasError = true;
// importPreviewOutput.Results.Add((false, "名称重复"));
// return Task.CompletedTask;
//}
//转化设备名称
item.TryGetValue(ExportHelpers.DeviceName, out var value);
var deviceName = value?.ToString();
cacheDeviceDicts.TryGetValue(deviceName, out var device);
var deviceId = device?.Id;
if (deviceId == null)
{
//找不到对应的设备
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), false, $"{deviceName}设备不存在"));
return;
}
else
{
//变量ID和设备ID都需要手动补录
variable.DeviceId = deviceId.Value;
variable.Id = dbVariableDicts.TryGetValue(variable.Name, out var dbvar1) ? dbvar1.Id : YitIdHelper.NextId();
}
variables.Add(variable);
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), true, "成功"));
}
catch (Exception ex)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), false, ex.Message));
}
});
importPreviewOutput.Data = variables.OrderBy(a => a.Id).ToDictionary(a => a.Name);
}
else
{
int row = 1;
ImportPreviewOutput<string> importPreviewOutput = new();
ImportPreviews.Add(sheetName, importPreviewOutput);
//插件属性需加上前置名称
var newName = ExportHelpers.PluginLeftName + sheetName;
var pluginId = _driverPluginService.GetIdByName(newName);
try
{
if (pluginId == null)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), false, $"插件{newName}不存在"));
continue;
}
var driverPlugin = _driverPluginService.GetDriverPluginById(pluginId.Value);
using var serviceScope = _scopeFactory.CreateScope();
var pluginSingletonService = serviceScope.ServiceProvider.GetService<PluginSingletonService>();
var driver = (UpLoadBase)pluginSingletonService.GetDriver(YitIdHelper.NextId(), driverPlugin);
var propertys = driver.VariablePropertys.GetType().GetAllProps()
.Where(a => a.GetCustomAttribute<VariablePropertyAttribute>() != null)
.ToDictionary(a => a.FindDisplayAttribute(a => a.GetCustomAttribute<VariablePropertyAttribute>()?.Description));
var cacheUpdeviceDicts = _uploadDeviceService.GetCacheList().ToDictionary(a => a.Name);
rows.ParallelForEach(item =>
{
try
{
List<DependencyProperty> dependencyProperties = new List<DependencyProperty>();
foreach (var keyValuePair in item)
{
if (propertys.TryGetValue(keyValuePair.Key, out var propertyInfo))
{
dependencyProperties.Add(new()
{
PropertyName = propertyInfo.Name,
Description = keyValuePair.Key.ToString(),
Value = keyValuePair.Value?.ToString()
});
}
}
//转化插件名称
item.TryGetValue(ExportHelpers.DeviceVariableSheetName, out var variableNameObj);
item.TryGetValue(ExportHelpers.UploadDeviceSheetName, out var uploadDevName);
var variableName = variableNameObj?.ToString();
if (uploadDevName != null)
{
cacheUpdeviceDicts.TryGetValue(uploadDevName.ToString(), out var uploadDevice);
var has = deviceImportPreview.Data.TryGetValue(variableName, out var deviceVariable);
if (has)
{
if (uploadDevice != null)
{
deviceVariable.VariablePropertys?.AddOrUpdate(uploadDevice.Id, a => dependencyProperties, (a, b) => dependencyProperties);
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), true, "成功"));
}
else
{
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), true, $"上传设备{uploadDevName}不存在"));
}
}
else
{
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), true, $"上传设备{uploadDevName}不存在"));
}
}
else
{
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), true, $"上传设备{uploadDevName}不存在"));
}
}
catch (Exception ex)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), false, ex.Message));
}
});
}
catch (Exception ex)
{
importPreviewOutput.HasError = true;
importPreviewOutput.Results.Add((Interlocked.Add(ref row, 1), false, ex.Message));
}
}
}
@@ -667,28 +814,16 @@ public class VariableService : DbRepository<DeviceVariable>, IVariableService
if (item.Key == ExportHelpers.DeviceVariableSheetName)
{
var collectDeviceImports = ((ImportPreviewOutput<DeviceVariable>)item.Value).Data;
collectDevices = collectDeviceImports.Adapt<List<DeviceVariable>>();
collectDevices = collectDeviceImports.Values.ToList();
break;
}
}
if (Context.CurrentConnectionConfig.DbType == DbType.Sqlite
|| Context.CurrentConnectionConfig.DbType == DbType.SqlServer
|| Context.CurrentConnectionConfig.DbType == DbType.MySql
|| Context.CurrentConnectionConfig.DbType == DbType.PostgreSQL
)
await Context.Utilities.PageEachAsync(collectDevices, 10000, async pageList =>
{
//大量数据插入/更新
var x = await Context.Storageable(collectDevices).ToStorageAsync();
await x.BulkCopyAsync();//不存在插入
await x.BulkUpdateAsync();//存在更新
}
else
{
//其他数据库使用普通插入/更新
await Context.Storageable(collectDevices).ExecuteCommandAsync();
}
await Context.Storageable(pageList).ExecuteCommandAsync();
});
DeleteVariableFromCache();
await Task.CompletedTask;
}

View File

@@ -532,10 +532,10 @@ public class AlarmWorker : BackgroundService
_logger.LogWarning(ex, "写入历史报警失败");
var cacheDatas = hisalarm.ChunkTrivialBetter(500);
await cacheDatas.ForeachAsync(async a =>
foreach (var a in cacheDatas)
{
await CacheDb.AddCacheData("", a.ToJson(), 50000);
});
}
}
}

View File

@@ -356,6 +356,8 @@ public class CollectDeviceCore : DisposableObject
{
foreach (var deviceVariableSourceRead in DeviceVariableSourceReads)
{
await Task.Delay(10);
if (Device?.KeepRun == false)
{
continue;
@@ -381,11 +383,11 @@ public class CollectDeviceCore : DisposableObject
}
}
}
foreach (var deviceVariableMedRead in DeviceVariableMedReads)
{
await Task.Delay(10);
if (Device?.KeepRun == false)
continue;
if (StoppingToken.IsCancellationRequested)
@@ -738,8 +740,7 @@ public class CollectDeviceCore : DisposableObject
{
_pluginService.DeleteDriver(DeviceId, Device.PluginId);
}
GC.Collect();
GC.WaitForPendingFinalizers();
}

View File

@@ -84,6 +84,7 @@ public class CollectDeviceThread : IDisposable
{
await device.BeforeActionAsync(StoppingToken.Token);
}
await Task.Delay(100, StoppingToken.Token);
}
while (!CollectDeviceCores.All(a => a.IsExited))
{

View File

@@ -93,6 +93,8 @@ public class CollectDeviceWorker : BackgroundService
StartAllDeviceThreads();
_logger.LogInformation("启动其他服务线程");
StartOtherHostService();
GC.Collect();
GC.WaitForPendingFinalizers();
}
catch (Exception ex)
{
@@ -229,6 +231,7 @@ public class CollectDeviceWorker : BackgroundService
deviceCollectCore.Init(collectDeviceRunTime);
DeviceThread(deviceCollectCore);
await Task.Delay(10);
}
catch (Exception ex)
{
@@ -483,51 +486,61 @@ public class CollectDeviceWorker : BackgroundService
await RestartDeviceThreadAsync();
while (!stoppingToken.IsCancellationRequested)
{
//这里不采用CancellationToken控制子线程直接循环保持结束时调用子设备线程Dispose
//检测设备采集线程假死
var num = CollectDeviceCores.Count;
for (int i = 0; i < num; i++)
try
{
CollectDeviceCore devcore = CollectDeviceCores[i];
if (devcore.Device != null)
//这里不采用CancellationToken控制子线程直接循环保持结束时调用子设备线程Dispose
//检测设备采集线程假死
var num = CollectDeviceCores.Count;
for (int i = 0; i < num; i++)
{
if (
(devcore.Device.ActiveTime != DateTime.MinValue
&& devcore.Device.ActiveTime.AddMinutes(3) <= DateTime.UtcNow)
|| devcore.IsInitSuccess == false
)
CollectDeviceCore devcore = CollectDeviceCores[i];
if (devcore.Device != null)
{
if (devcore.StoppingTokens.LastOrDefault()?.Token.IsCancellationRequested == true)
continue;
if (devcore.Device.DeviceStatus == DeviceStatusEnum.Pause)
continue;
if (!devcore.IsInitSuccess)
_logger?.LogWarning(devcore.Device.Name + "初始化失败,重启线程中");
else
_logger?.LogWarning(devcore.Device.Name + "采集线程假死,重启线程中");
await UpDeviceThreadAsync(devcore.DeviceId, false);
break;
}
else
{
_logger?.LogTrace(devcore.Device.Name + "线程检测正常");
}
if (devcore.Device.DeviceStatus == DeviceStatusEnum.OffLine)
{
if (devcore.Device.IsRedundant && _collectDeviceService.GetCacheList().Any(a => a.Id == devcore.Device.RedundantDeviceId))
if (
(devcore.Device.ActiveTime != DateTime.MinValue
&& devcore.Device.ActiveTime.AddMinutes(3) <= DateTime.UtcNow)
|| devcore.IsInitSuccess == false
)
{
await UpDeviceRedundantThreadAsync(devcore.Device.Id);
if (devcore.StoppingTokens.LastOrDefault()?.Token.IsCancellationRequested == true)
continue;
if (devcore.Device.DeviceStatus == DeviceStatusEnum.Pause)
continue;
if (!devcore.IsInitSuccess)
_logger?.LogWarning(devcore.Device.Name + "初始化失败,重启线程中");
else
_logger?.LogWarning(devcore.Device.Name + "采集线程假死,重启线程中");
await UpDeviceThreadAsync(devcore.DeviceId, false);
break;
}
else
{
_logger?.LogTrace(devcore.Device.Name + "线程检测正常");
}
if (devcore.Device.DeviceStatus == DeviceStatusEnum.OffLine)
{
if (devcore.Device.IsRedundant && _collectDeviceService.GetCacheList().Any(a => a.Id == devcore.Device.RedundantDeviceId))
{
await UpDeviceRedundantThreadAsync(devcore.Device.Id);
}
}
}
}
await Task.Delay(300000, stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, ToString());
}
await Task.Delay(300000, stoppingToken);
}
}

View File

@@ -21,7 +21,6 @@ using System.Linq;
using System.Reflection;
using System.Threading;
using ThingsGateway.Core.Extension;
using ThingsGateway.Foundation;
using ThingsGateway.Foundation.Extension;
using ThingsGateway.Foundation.Extension.Enumerator;
@@ -245,11 +244,10 @@ public class HistoryValueWorker : BackgroundService
if (LastIsSuccess)
_logger.LogWarning(ex, "写入历史数据失败");
var cacheDatas = collecthis.ChunkTrivialBetter(500);
await cacheDatas.ForeachAsync(async a =>
{
await CacheDb.AddCacheData("", a.ToJson(), 50000);
});
foreach (var a in cacheDatas)
{
await CacheDb.AddCacheData("", a.ToJson(), 50000);
}
}
}
@@ -273,10 +271,10 @@ public class HistoryValueWorker : BackgroundService
if (LastIsSuccess)
_logger.LogWarning(ex, "写入历史数据失败");
var cacheDatas = changehis.ChunkTrivialBetter(500);
await cacheDatas.ForeachAsync(async a =>
foreach (var a in cacheDatas)
{
await CacheDb.AddCacheData("", a.ToJson(), 50000);
});
}
}
}

View File

@@ -69,6 +69,7 @@ public class UploadDeviceThread : IDisposable
{
device.Logger?.LogError(ex, "报文日志添加失败");
}
await Task.Delay(100, StoppingToken.Token);
await device.BeforeActionAsync(StoppingToken.Token);
}
while (!UploadDeviceCores.All(a => a.IsExited))

View File

@@ -354,39 +354,48 @@ public class UploadDeviceWorker : BackgroundService
while (!stoppingToken.IsCancellationRequested)
{
//这里不采用CancellationToken控制子线程直接循环保持结束时调用子设备线程Dispose
//检测设备上传线程假死
var num = UploadDeviceCores.Count;
for (int i = 0; i < num; i++)
try
{
UploadDeviceCore devcore = UploadDeviceCores[i];
if (devcore.Device != null)
//这里不采用CancellationToken控制子线程直接循环保持结束时调用子设备线程Dispose
//检测设备上传线程假死
var num = UploadDeviceCores.Count;
for (int i = 0; i < num; i++)
{
if (
(devcore.Device.ActiveTime != DateTime.MinValue
&& devcore.Device.ActiveTime.AddMinutes(3) <= DateTime.UtcNow)
|| devcore.IsInitSuccess == false
)
UploadDeviceCore devcore = UploadDeviceCores[i];
if (devcore.Device != null)
{
if (devcore.StoppingTokens.LastOrDefault()?.Token.IsCancellationRequested == true)
continue;
if (devcore.Device.DeviceStatus == DeviceStatusEnum.Pause)
continue;
if (!devcore.IsInitSuccess)
_logger?.LogWarning(devcore.Device.Name + "初始化失败,重启线程中");
if (
(devcore.Device.ActiveTime != DateTime.MinValue
&& devcore.Device.ActiveTime.AddMinutes(3) <= DateTime.UtcNow)
|| devcore.IsInitSuccess == false
)
{
if (devcore.StoppingTokens.LastOrDefault()?.Token.IsCancellationRequested == true)
continue;
if (devcore.Device.DeviceStatus == DeviceStatusEnum.Pause)
continue;
if (!devcore.IsInitSuccess)
_logger?.LogWarning(devcore.Device.Name + "初始化失败,重启线程中");
else
_logger?.LogWarning(devcore.Device.Name + "上传线程假死,重启线程中");
await UpDeviceThreadAsync(devcore.DeviceId);
}
else
_logger?.LogWarning(devcore.Device.Name + "上传线程假死,重启线程中");
await UpDeviceThreadAsync(devcore.DeviceId);
{
_logger?.LogTrace(devcore.Device.Name + "线程检测正常");
}
}
}
else
{
_logger?.LogTrace(devcore.Device.Name + "线程检测正常");
}
}
await Task.Delay(300000, stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, ToString());
}
await Task.Delay(300000, stoppingToken);
}
}

View File

@@ -185,12 +185,16 @@ namespace ThingsGateway.Web.Page
{
try
{
if (_collectDeviceCores?.FirstOrDefault()?.Device == null)
{
_collectDeviceGroups = _globalDeviceData.CollectDevices.Adapt<List<CollectDevice>>()?.Select(a => a.DeviceGroup)?.Where(a => a != null).Distinct()?.ToList() ?? new();
_collectDeviceCores = CollectDeviceHostService?.CollectDeviceCores?.WhereIf(!_collectDeviceGroup.IsNullOrEmpty(), a => a.Device?.DeviceGroup == _collectDeviceGroup).ToList() ?? new();
}
if (_collectDeviceCores?.FirstOrDefault()?.Device == null || CollectDeviceHostService?.CollectDeviceCores.Count != _collectDeviceCores.Count)
{
collectDeviceQuery();
}
if (_uploadDeviceCores?.FirstOrDefault()?.Device == null)
if (_uploadDeviceCores?.FirstOrDefault()?.Device == null || UploadDeviceHostService?.UploadDeviceCores.Count != _uploadDeviceCores.Count)
{
uploadDeviceQuery();
}

View File

@@ -488,7 +488,7 @@
var data=GetDriverProperties(UploadDevices.FirstOrDefault(a=>a.Id==choiceUploadDeviceId).PluginId,context.VariablePropertys.ContainsKey(choiceUploadDeviceId)?context.VariablePropertys[choiceUploadDeviceId]:null);
if(data?.Count>0)
{
context.VariablePropertys.AddOrUpdate(choiceUploadDeviceId, data);
context.VariablePropertys.AddOrUpdate(choiceUploadDeviceId,a=> data,(a,b)=>data);
}
else
{

View File

@@ -48,6 +48,7 @@ namespace ThingsGateway.Web.Page
{
isImport = true;
StateHasChanged();
ImportPreviews.Clear();
ImportPreviews = await Preview.Invoke(file);
Step = 2;
}

View File

@@ -396,7 +396,7 @@
var data=GetDriverProperties(UploadDevices.FirstOrDefault(a=>a.Id==choiceUploadDeviceId).PluginId,context.VariablePropertys.ContainsKey(choiceUploadDeviceId)?context.VariablePropertys[choiceUploadDeviceId]:null);
if(data?.Count>0)
{
context.VariablePropertys.AddOrUpdate(choiceUploadDeviceId, data);
context.VariablePropertys.AddOrUpdate(choiceUploadDeviceId,a=> data,(a,b)=>data);
}
else
{

View File

@@ -26,7 +26,8 @@ public class Program
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
System.IO.Directory.SetCurrentDirectory(AppContext.BaseDirectory);
ThreadPool.SetMinThreads(2000, 2000);
ThreadPool.SetMaxThreads(1000000, 1000000);
#if KINGVIEW //读取组态王不能后台启动,所以这里多出来一个解决方案配置
SevicesExtension.KINGVIEWCONFIG();

View File

@@ -11,7 +11,7 @@
<ApplicationIcon>favicon.ico</ApplicationIcon>
<Configurations>Debug;Release;KINGVIEW</Configurations>
<Platforms>AnyCPU;x86</Platforms>
<ServerGarbageCollection>false</ServerGarbageCollection>
<!--<ServerGarbageCollection>false</ServerGarbageCollection>-->
<!--切换为工作站GC策略-->
</PropertyGroup>