本文介绍如何使用C#和LiteDB实现一个轻量级的工业设备数据记录系统。LiteDB是一个开源的NoSQL嵌入式数据库,类似于MongoDB,但更轻量级,非常适合用于小型工业设备数据采集场景。
Bash# 通过NuGet安装LiteDB包
Install-Package LiteDB

C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LiteDB;
namespace App15
{
// 设备数据模型
public class DeviceData
{
public ObjectId Id { get; set; } // 文档ID
public string DeviceId { get; set; } // 设备ID
public DateTime Timestamp { get; set; } // 时间戳
public double Temperature { get; set; } // 温度
public double Humidity { get; set; } // 湿度
public double Pressure { get; set; } // 压力
public string Status { get; set; } // 设备状态
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LiteDB;
namespace App15
{
// 设备告警模型
public class DeviceAlarm
{
public ObjectId Id { get; set; }
public string DeviceId { get; set; }
public DateTime AlarmTime { get; set; }
public string AlarmType { get; set; }
public string AlarmMessage { get; set; }
public bool IsHandled { get; set; }
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LiteDB;
namespace App15
{
public class DatabaseConfig
{
public static ConnectionString GetSharedConnectionString(string dbPath)
{
return new ConnectionString
{
Filename = dbPath,
Connection= LiteDB.ConnectionType.Shared,//这里很重要,默认是独享的
};
}
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LiteDB;
namespace App15
{
public class DeviceDataRepository
{
private readonly string _dbPath;
private readonly string _collectionName;
public DeviceDataRepository(string dbPath, string collectionName)
{
_dbPath = dbPath;
_collectionName = collectionName;
}
// 插入单条数据
public void Insert(DeviceData data)
{
using (var db = new LiteDatabase(DatabaseConfig.GetSharedConnectionString(_dbPath)))
{
var collection = db.GetCollection<DeviceData>(_collectionName);
collection.Insert(data);
}
}
// 批量插入数据
public void InsertBatch(IEnumerable<DeviceData> dataList)
{
using (var db = new LiteDatabase(DatabaseConfig.GetSharedConnectionString(_dbPath)))
{
var collection = db.GetCollection<DeviceData>(_collectionName);
collection.InsertBulk(dataList);
}
}
// 查询指定时间范围的数据
public IEnumerable<DeviceData> QueryByTimeRange(DateTime startTime, DateTime endTime)
{
using (var db = new LiteDatabase(DatabaseConfig.GetSharedConnectionString(_dbPath)))
{
var collection = db.GetCollection<DeviceData>(_collectionName);
return collection.Find(x => x.Timestamp >= startTime && x.Timestamp <= endTime);
}
}
// 查询指定设备的最新数据
public DeviceData GetLatestData(string deviceId)
{
using (var db = new LiteDatabase(DatabaseConfig.GetSharedConnectionString(_dbPath)))
{
var collection = db.GetCollection<DeviceData>(_collectionName);
return collection.FindOne(Query.All(Query.Descending));
}
}
// 删除过期数据
public int DeleteOldData(DateTime beforeTime)
{
using (var db = new LiteDatabase(DatabaseConfig.GetSharedConnectionString(_dbPath)))
{
var collection = db.GetCollection<DeviceData>(_collectionName);
return collection.DeleteMany(x => x.Timestamp < beforeTime);
}
}
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LiteDB;
namespace App15
{
public class AlarmManager
{
private readonly string _dbPath;
private readonly string _collectionName = "device_alarms";
public AlarmManager(string dbPath)
{
_dbPath = dbPath;
}
// 创建告警
public void CreateAlarm(DeviceAlarm alarm)
{
using (var db = new LiteDatabase(DatabaseConfig.GetSharedConnectionString(_dbPath)))
{
var collection = db.GetCollection<DeviceAlarm>(_collectionName);
collection.Insert(alarm);
}
}
// 获取未处理的告警
public IEnumerable<DeviceAlarm> GetUnhandledAlarms()
{
using (var db = new LiteDatabase(DatabaseConfig.GetSharedConnectionString(_dbPath)))
{
var collection = db.GetCollection<DeviceAlarm>(_collectionName);
return collection.Find(x => !x.IsHandled);
}
}
// 标记告警为已处理
public bool HandleAlarm(ObjectId alarmId)
{
using (var db = new LiteDatabase(DatabaseConfig.GetSharedConnectionString(_dbPath)))
{
var collection = db.GetCollection<DeviceAlarm>(_collectionName);
var alarm = collection.FindById(alarmId);
if (alarm != null)
{
alarm.IsHandled = true;
return collection.Update(alarm);
}
return false;
}
}
}
}
C#public class DataCollectionService
{
private readonly DeviceDataRepository _repository;
private readonly AlarmManager _alarmManager;
private readonly Timer _timer;
private readonly string _deviceId;
public DataCollectionService(string dbPath, string deviceId)
{
_repository = new DeviceDataRepository(dbPath, "device_data");
_alarmManager = new AlarmManager(dbPath);
_deviceId = deviceId;
// 创建定时器,每5秒采集一次数据
_timer = new Timer(CollectData, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
}
private void CollectData(object state)
{
try
{
// 模拟从设备读取数据
var data = ReadDeviceData();
// 存储数据
_repository.Insert(data);
// 检查是否需要产生告警
CheckAlarmConditions(data);
}
catch (Exception ex)
{
// 记录异常
Console.WriteLine($"数据采集异常: {ex.Message}");
}
}
private DeviceData ReadDeviceData()
{
// 这里模拟从实际设备读取数据
// 实际应用中需要替换为真实的设备通信代码
Random rand = new Random();
return new DeviceData
{
DeviceId = _deviceId,
Timestamp = DateTime.Now,
Temperature = 20 + rand.NextDouble() * 10,
Humidity = 40 + rand.NextDouble() * 20,
Pressure = 101 + rand.NextDouble() * 2,
Status = "Running"
};
}
private void CheckAlarmConditions(DeviceData data)
{
// 检查温度是否超过阈值
if (data.Temperature > 28)
{
_alarmManager.CreateAlarm(new DeviceAlarm
{
DeviceId = data.DeviceId,
AlarmTime = DateTime.Now,
AlarmType = "HighTemperature",
AlarmMessage = $"温度过高: {data.Temperature:F2}°C",
IsHandled = false
});
}
// 检查湿度是否超过阈值
if (data.Humidity > 55)
{
_alarmManager.CreateAlarm(new DeviceAlarm
{
DeviceId = data.DeviceId,
AlarmTime = DateTime.Now,
AlarmType = "HighHumidity",
AlarmMessage = $"湿度过高: {data.Humidity:F2}%",
IsHandled = false
});
}
}
}
C#class Program
{
static void Main(string[] args)
{
string dbPath = "DeviceData.db";
string deviceId = "Device001";
// 启动数据采集服务
var dataCollectionService = new DataCollectionService(dbPath, deviceId);
// 创建数据访问对象
var repository = new DeviceDataRepository(dbPath, "device_data");
var alarmManager = new AlarmManager(dbPath);
// 演示查询最近1小时的数据
var endTime = DateTime.Now;
var startTime = endTime.AddHours(-1);
var recentData = repository.QueryByTimeRange(startTime, endTime);
foreach (var data in recentData)
{
Console.WriteLine($"时间: {data.Timestamp}, 温度: {data.Temperature:F2}°C, " +
$"湿度: {data.Humidity:F2}%, 压力: {data.Pressure:F2}kPa");
}
// 查看未处理的告警
var unhandledAlarms = alarmManager.GetUnhandledAlarms();
foreach (var alarm in unhandledAlarms)
{
Console.WriteLine($"告警时间: {alarm.AlarmTime}, 类型: {alarm.AlarmType}, " +
$"消息: {alarm.AlarmMessage}");
}
Console.WriteLine("按任意键退出...");
Console.ReadKey();
}
}

批量插入:当需要插入大量数据时,使用InsertBulk而不是单条插入。
索引优化:为常用查询字段创建索引:
C#collection.EnsureIndex(x => x.DeviceId); collection.EnsureIndex(x => x.Timestamp);
定期清理:实现数据清理策略,定期删除过期数据:
C#// 删除30天前的数据
repository.DeleteOldData(DateTime.Now.AddDays(-30));
连接复用:对于高频操作,考虑复用数据库连接:
C#public class OptimizedRepository
{
private readonly LiteDatabase _db;
public OptimizedRepository(string dbPath)
{
_db = new LiteDatabase(dbPath);
}
public void Dispose()
{
_db?.Dispose();
}
}
本文介绍了如何使用LiteDB实现一个简单但完整的工业设备数据记录系统。该系统具有以下特点:
LiteDB的优势在于其简单性和可靠性,非常适合小型工业现场的数据采集需求。通过合理的架构设计和优化,可以构建出一个高效、可靠的数据记录系统。
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!