You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
360 lines
9.7 KiB
360 lines
9.7 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace SunlightCentralizedControlManagement_SCCM_.UserClass
|
|
{
|
|
/// <summary>
|
|
/// 线程安全的 DataTable 管理器
|
|
/// 提供对 DataTable 的安全并发访问
|
|
/// </summary>
|
|
public class DataTableManager : IDisposable
|
|
{
|
|
private DataTable _dataTable;
|
|
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
|
private bool _disposed = false;
|
|
|
|
#region 构造函数
|
|
public DataTableManager()
|
|
{
|
|
_dataTable = new DataTable();
|
|
}
|
|
|
|
public DataTableManager(DataTable dataTable)
|
|
{
|
|
_dataTable = dataTable ?? throw new ArgumentNullException(nameof(dataTable));
|
|
}
|
|
|
|
public DataTableManager(string tableName)
|
|
{
|
|
_dataTable = new DataTable(tableName);
|
|
}
|
|
#endregion
|
|
|
|
#region 基本操作
|
|
/// <summary>
|
|
/// 安全地添加列
|
|
/// </summary>
|
|
public void AddColumn(string columnName, Type dataType)
|
|
{
|
|
ExecuteWriteOperation(table =>
|
|
{
|
|
table.Columns.Add(columnName, dataType);
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 安全地添加行
|
|
/// </summary>
|
|
public void AddRow(params object[] values)
|
|
{
|
|
ExecuteWriteOperation(table =>
|
|
{
|
|
DataRow newRow = table.NewRow();
|
|
for (int i = 0; i < Math.Min(values.Length, table.Columns.Count); i++)
|
|
{
|
|
newRow[i] = values[i] ?? DBNull.Value;
|
|
}
|
|
table.Rows.Add(newRow);
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 安全地更新单元格值
|
|
/// </summary>
|
|
public bool UpdateCell(int rowIndex, string columnName, object value)
|
|
{
|
|
return ExecuteWriteOperation(table =>
|
|
{
|
|
if (IsValidRowIndex(table, rowIndex) && table.Columns.Contains(columnName))
|
|
{
|
|
table.Rows[rowIndex][columnName] = value ?? DBNull.Value;
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 安全地删除行
|
|
/// </summary>
|
|
public bool DeleteRow(int rowIndex)
|
|
{
|
|
return ExecuteWriteOperation(table =>
|
|
{
|
|
if (IsValidRowIndex(table, rowIndex))
|
|
{
|
|
table.Rows[rowIndex].Delete();
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
#endregion
|
|
|
|
#region 查询操作
|
|
/// <summary>
|
|
/// 安全地获取行
|
|
/// </summary>
|
|
public DataRow GetRow(int rowIndex)
|
|
{
|
|
return ExecuteReadOperation(table =>
|
|
{
|
|
return IsValidRowIndex(table, rowIndex) ? table.Rows[rowIndex] : null;
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 安全地查找行(使用筛选条件)
|
|
/// </summary>
|
|
public DataRow[] FindRows(string filterExpression)
|
|
{
|
|
return ExecuteReadOperation(table =>
|
|
{
|
|
try
|
|
{
|
|
return string.IsNullOrEmpty(filterExpression)
|
|
? table.Select()
|
|
: table.Select(filterExpression);
|
|
}
|
|
catch (EvaluateException)
|
|
{
|
|
return new DataRow[0];
|
|
}
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 安全地获取行数
|
|
/// </summary>
|
|
public int GetRowCount()
|
|
{
|
|
return ExecuteReadOperation(table => table.Rows.Count);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 安全地检查行是否存在
|
|
/// </summary>
|
|
public bool RowExists(int rowIndex)
|
|
{
|
|
return ExecuteReadOperation(table => IsValidRowIndex(table, rowIndex));
|
|
}
|
|
#endregion
|
|
|
|
#region 批量操作
|
|
/// <summary>
|
|
/// 安全地批量添加行
|
|
/// </summary>
|
|
public void BulkAddRows(IEnumerable<object[]> rowsData)
|
|
{
|
|
ExecuteWriteOperation(table =>
|
|
{
|
|
foreach (var rowData in rowsData)
|
|
{
|
|
DataRow newRow = table.NewRow();
|
|
for (int i = 0; i < Math.Min(rowData.Length, table.Columns.Count); i++)
|
|
{
|
|
newRow[i] = rowData[i] ?? DBNull.Value;
|
|
}
|
|
table.Rows.Add(newRow);
|
|
}
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 安全地清空所有数据
|
|
/// </summary>
|
|
public void Clear()
|
|
{
|
|
ExecuteWriteOperation(table =>
|
|
{
|
|
table.Clear();
|
|
});
|
|
}
|
|
#endregion
|
|
|
|
#region 数据导出
|
|
/// <summary>
|
|
/// 获取数据快照(线程安全的副本)
|
|
/// </summary>
|
|
public DataTable GetSnapshot()
|
|
{
|
|
return ExecuteReadOperation(table =>
|
|
{
|
|
return table.Copy(); // 创建数据的独立副本
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取只读视图
|
|
/// </summary>
|
|
public DataView GetReadOnlyView()
|
|
{
|
|
return ExecuteReadOperation(table =>
|
|
{
|
|
return new DataView(table) { AllowEdit = false };
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 导出到新 DataTable(包含结构)
|
|
/// </summary>
|
|
public DataTable ExportToDataTable()
|
|
{
|
|
return ExecuteReadOperation(table =>
|
|
{
|
|
DataTable exported = table.Clone();
|
|
exported.Merge(table, false, MissingSchemaAction.Add);
|
|
return exported;
|
|
});
|
|
}
|
|
#endregion
|
|
|
|
#region 锁操作核心
|
|
/// <summary>
|
|
/// 执行读取操作(共享锁)
|
|
/// </summary>
|
|
private T ExecuteReadOperation<T>(Func<DataTable, T> operation)
|
|
{
|
|
_lock.EnterReadLock();
|
|
try
|
|
{
|
|
return operation(_dataTable);
|
|
}
|
|
finally
|
|
{
|
|
_lock.ExitReadLock();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 执行写入操作(独占锁)
|
|
/// </summary>
|
|
private void ExecuteWriteOperation(Action<DataTable> operation)
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
operation(_dataTable);
|
|
_dataTable.AcceptChanges();
|
|
}
|
|
finally
|
|
{
|
|
_lock.ExitWriteLock();
|
|
}
|
|
}
|
|
|
|
private T ExecuteWriteOperation<T>(Func<DataTable, T> operation)
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
var result = operation(_dataTable);
|
|
_dataTable.AcceptChanges();
|
|
return result;
|
|
}
|
|
finally
|
|
{
|
|
_lock.ExitWriteLock();
|
|
}
|
|
}
|
|
|
|
private bool IsValidRowIndex(DataTable table, int rowIndex)
|
|
{
|
|
return rowIndex >= 0 && rowIndex < table.Rows.Count;
|
|
}
|
|
#endregion
|
|
|
|
#region 高级功能
|
|
/// <summary>
|
|
/// 带超时的安全操作
|
|
/// </summary>
|
|
public bool TryUpdateCell(int rowIndex, string columnName, object value, int timeoutMs = 5000)
|
|
{
|
|
if (_lock.TryEnterWriteLock(timeoutMs))
|
|
{
|
|
try
|
|
{
|
|
if (IsValidRowIndex(_dataTable, rowIndex) && _dataTable.Columns.Contains(columnName))
|
|
{
|
|
_dataTable.Rows[rowIndex][columnName] = value ?? DBNull.Value;
|
|
_dataTable.AcceptChanges();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
finally
|
|
{
|
|
_lock.ExitWriteLock();
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 执行事务性操作
|
|
/// </summary>
|
|
public void ExecuteTransaction(Action<DataTable> transaction)
|
|
{
|
|
_lock.EnterWriteLock();
|
|
try
|
|
{
|
|
// 开始事务
|
|
_dataTable.BeginLoadData();
|
|
|
|
try
|
|
{
|
|
transaction(_dataTable);
|
|
_dataTable.AcceptChanges();
|
|
}
|
|
catch
|
|
{
|
|
_dataTable.RejectChanges();
|
|
throw;
|
|
}
|
|
finally
|
|
{
|
|
_dataTable.EndLoadData();
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
_lock.ExitWriteLock();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region 属性和清理
|
|
public string TableName
|
|
{
|
|
get => ExecuteReadOperation(table => table.TableName);
|
|
set => ExecuteWriteOperation(table => table.TableName = value);
|
|
}
|
|
|
|
public DataColumnCollection Columns
|
|
{
|
|
get => ExecuteReadOperation(table => table.Columns);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (!_disposed)
|
|
{
|
|
_lock?.Dispose();
|
|
_dataTable?.Dispose();
|
|
_disposed = true;
|
|
}
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
~DataTableManager()
|
|
{
|
|
Dispose();
|
|
}
|
|
#endregion
|
|
}
|
|
}
|
|
|