暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

LiteDB在电气自动化数据存储中的实践指南

技术老小子 2025-02-26
7

背景介绍

在电气自动化系统中,数据存储是至关重要的环节。传统的关系型数据库往往过于复杂,而嵌入式数据库LiteDB以其轻量、高效、无服务器的特点,成为电气自动化领域数据存储的理想选择。

项目结构

App/
├── Models/
│   ├── DeviceLog.cs
│   ├── DeviceConfig.cs
│   └── HistoricalData.cs
├── Services/
│   ├── LogService.cs
│   ├── ConfigService.cs
│   └── DataRecordService.cs
└── Program.cs
└── DatabaseFactory.cs

复制

设备运行日志存储

模型定义

/// <summary>
/// 日志级别枚举
/// </summary>
public enum LogLevel
{
    Info,
    Warning,
    Error,
    Critical
}

/// <summary>
/// 设备运行日志实体
/// </summary>
public class DeviceLog
{

    public int Id { get; set; }

    /// <summary>
    /// 设备唯一标识
    /// </summary>
    public string DeviceId { get; set; }

    /// <summary>
    /// 日志级别
    /// </summary>
    public LogLevel Level { get; set; }

    /// <summary>
    /// 日志内容
    /// </summary>
    public string Message { get; set; }

    /// <summary>
    /// 发生时间
    /// </summary>
    public DateTime Timestamp { get; set; }
}

复制

日志服务实现

public class LogService
{

    private readonly ILiteCollection<DeviceLog> _logCollection;
    public LogService()
    
{
        _logCollection = DatabaseFactory.GetDatabase().GetCollection<DeviceLog>("device_logs");

        // 创建索引以提高查询性能
        _logCollection.EnsureIndex(x => x.DeviceId);
        _logCollection.EnsureIndex(x => x.Timestamp);
    }

    /// <summary>
    /// 记录设备日志
    /// </summary>
    public void LogDeviceEvent(string deviceId, LogLevel level, string message)
    
{
        var log = new DeviceLog
        {
            DeviceId = deviceId,
            Level = level,
            Message = message,
            Timestamp = DateTime.Now
        };

        _logCollection.Insert(log);
    }

    /// <summary>
    /// 查询特定设备的日志
    /// </summary>
    public IEnumerable<DeviceLog> GetDeviceLogs(string deviceId,
        DateTime? startTime = null,
        DateTime? endTime = null,
        LogLevel? level = null)
    {
        var query = _logCollection.Query()
            .Where(x => x.DeviceId == deviceId);

        if (startTime.HasValue)
            query = query.Where(x => x.Timestamp >= startTime.Value);

        if (endTime.HasValue)
            query = query.Where(x => x.Timestamp <= endTime.Value);

        if (level.HasValue)
            query = query.Where(x => x.Level == level.Value);

        return query.ToList();
    }
}

复制

参数配置管理

模型定义

/// <summary>
/// 设备配置实体
/// </summary>
public class DeviceConfig
{

    public int Id { get; set; }

    /// <summary>
    /// 设备类型
    /// </summary>
    public string DeviceType { get; set; }

    /// <summary>
    /// 配置名称
    /// </summary>
    public string ConfigName { get; set; }

    /// <summary>
    /// 配置值
    /// </summary>
    public string ConfigValue { get; set; }

    /// <summary>
    /// 最后修改时间
    /// </summary>
    public DateTime LastModified { get; set; }
}

复制

配置服务实现

public class ConfigService
{

    private readonly ILiteCollection<DeviceConfig> _configCollection;
    public ConfigService()
    
{
        _configCollection = DatabaseFactory.GetDatabase().GetCollection<DeviceConfig>("device_configs");
        // 创建复合索引
        _configCollection.EnsureIndex(x => x.DeviceType);  
        _configCollection.EnsureIndex(x => x.ConfigName); 
    }

    /// <summary>
    /// 保存或更新配置
    /// </summary>
    public void SaveConfig(string deviceType, string configName, string configValue)
    
{
        var existingConfig = _configCollection.FindOne(
            x => x.DeviceType == deviceType && x.ConfigName == configName);

        if (existingConfig != null)
        {
            existingConfig.ConfigValue = configValue;
            existingConfig.LastModified = DateTime.Now;
            _configCollection.Update(existingConfig);
        }
        else
        {
            var newConfig = new DeviceConfig
            {
                DeviceType = deviceType,
                ConfigName = configName,
                ConfigValue = configValue,
                LastModified = DateTime.Now
            };
            _configCollection.Insert(newConfig);
        }
    }

    /// <summary>
    /// 获取配置
    /// </summary>
    public string GetConfig(string deviceType, string configName)
    
{
        var config = _configCollection.FindOne(
            x => x.DeviceType == deviceType && x.ConfigName == configName);

        return config?.ConfigValue;
    }

}

复制

历史数据记录

模型定义

/// <summary>
/// 历史数据记录
/// </summary>
public class HistoricalData
{

    public int Id { get; set; }

    /// <summary>
    /// 设备ID
    /// </summary>
    public string DeviceId { get; set; }

    /// <summary>
    /// 数据类型
    /// </summary>
    public string DataType { get; set; }

    /// <summary>
    /// 数值
    /// </summary>
    public double Value { get; set; }

    /// <summary>
    /// 记录时间
    /// </summary>
    public DateTime Timestamp { get; set; }
}

复制

历史数据服务

public class DataRecordService 
{

    private readonly ILiteCollection<HistoricalData> _dataCollection;
    public DataRecordService()
    
{
        _dataCollection = DatabaseFactory.GetDatabase().GetCollection<HistoricalData>("historical_data");

        // 创建索引
        _dataCollection.EnsureIndex(x => x.DeviceId);
        _dataCollection.EnsureIndex(x => x.Timestamp);
    }

    /// <summary>
    /// 记录历史数据
    /// </summary>
    public void RecordData(string deviceId, string dataType, double value)
    
{
        var historicalData = new HistoricalData
        {
            DeviceId = deviceId,
            DataType = dataType,
            Value = value,
            Timestamp = DateTime.Now
        };

        _dataCollection.Insert(historicalData);
    }

    /// <summary>
    /// 获取指定时间范围内的历史数据
    /// </summary>
    public IEnumerable<HistoricalData> GetHistoricalData(
        string deviceId,
        DateTime startTime,
        DateTime endTime,
        string dataType = null)
    {
        var query = _dataCollection.Query()
            .Where(x => x.DeviceId == deviceId)
            .Where(x => x.Timestamp >= startTime)
            .Where(x => x.Timestamp <= endTime);

        if (!string.IsNullOrEmpty(dataType))
        {
            query = query.Where(x => x.DataType == dataType);
        }

        return query.ToList();
    }

}

复制

离线数据缓存方案

模型定义

/// <summary>
/// 缓存数据实体
/// </summary>
public class CachedData
{

    public string Key { get; set; }
    public string Data { get; set; }
    public DateTime CachedTime { get; set; }
}

复制

离线缓存服务

public class OfflineCacheService
{

    private readonly ILiteCollection<CachedData> _cacheCollection;
    public OfflineCacheService()
    
{
        _cacheCollection = DatabaseFactory.GetDatabase().GetCollection<CachedData>("offline_cache");
    }

    /// <summary>
    /// 缓存数据
    /// </summary>
    public void CacheData(string key, object data)
    
{
        var cachedData = new CachedData
        {
            Key = key,
            Data = System.Text.Json.JsonSerializer.Serialize(data),
            CachedTime = DateTime.Now
        };

        _cacheCollection.Upsert(cachedData);
    }

    /// <summary>
    /// 获取缓存数据
    /// </summary>
    public T GetCachedData<T>(string key)
    {
        var cachedData = _cacheCollection.FindOne(x => x.Key == key);

        return cachedData != null
            ? System.Text.Json.JsonSerializer.Deserialize<T>(cachedData.Data)
            : default;
    }

    /// <summary>
    /// 清理过期缓存
    /// </summary>
    public void CleanupCache(TimeSpan maxAge)
    
{
        var expirationTime = DateTime.Now.Subtract(maxAge);
        _cacheCollection.DeleteMany(x => x.CachedTime < expirationTime);
    }
}

复制

工厂类

public class DatabaseFactory
{

    private static readonly object _lock = new object();
    private static LiteDatabase _database;
    private static string _dbPath;

    public static void Initialize(string dbPath)
    
{
        _dbPath = dbPath;
    }

    public static LiteDatabase GetDatabase()
    
{
        if (_database == null)
        {
            lock (_lock)
            {
                if (_database == null)
                {
                    _database = new LiteDatabase(_dbPath);
                }
            }
        }
        return _database;
    }

    public static void CloseDatabase()
    
{
        lock (_lock)
        {
            if (_database != null)
            {
                _database.Dispose();
                _database = null;
            }
        }
    }
}

复制

DatabaseFactory 类实现了一个线程安全的单例模式,用于管理数据库连接,确保资源的有效使用和安全访问。它解决了多线程环境下的资源共享问题,防止了文件访问冲突,并提供了集中的资源管理机制。这种设计模式在实际应用中非常常见,特别是在需要共享资源的场景中

主程序示例

internal class Program
{

    static void Main(string[] args)
    
{
        string dbPath = "electrical_automation.db";

        try
        {
            // 初始化数据库  
            DatabaseFactory.Initialize(dbPath);

            // 创建服务实例  
            var logService = new LogService();
            var configService = new ConfigService();
            var dataRecordService = new DataRecordService();
            var offlineCacheService = new OfflineCacheService();

            // 执行操作  
            logService.LogDeviceEvent("DEVICE001", LogLevel.Info, "系统启动");
            configService.SaveConfig("PLC""ScanInterval""500");
            dataRecordService.RecordData("DEVICE001""Temperature"25.5);
            offlineCacheService.CacheData("LastConfig"new { DeviceType = "PLC", Interval = 500 });
        }
        catch (Exception ex)
        {
            Console.WriteLine($"发生错误: {ex.Message}");
        }
        finally
        {
            // 确保关闭数据库连接  
            DatabaseFactory.CloseDatabase();
        }
    }
}

复制

总结

通过LiteDB,我们为电气自动化系统构建了一个轻量、高效的数据存储解决方案,涵盖了日志记录、配置管理、历史数据存储和离线缓存等关键场景。


如果你正在从事上位机、自动化、机器视觉、物联网(IOT)项目或数字化转型方面的工作,欢迎加入我的微信圈子!在这里,我们不仅可以轻松畅聊最新技术动态和行业趋势,还能够在技术问题上互相帮助和支持。我会尽量利用我的知识和经验来帮助你解决问题,当然也期待从大家的专业见解中学习和成长。无论你是新手还是老鸟,期待与志同道合的朋友交流心得,一起进步!


文章转载自技术老小子,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论