WPF 数据库 SQLite 分页处理

文章讲述了作者如何解决上位机主页面内存占用过高的问题,通过将接收到的报文数据暂存到SQLite数据库,设计了数据库读写操作,包括报文类的创建、数据库连接管理以及使用C#的ORM进行数据插入和分页查询。
摘要由CSDN通过智能技术生成

最近写的上位机主页面 因为需要展示收到的报文信息,所以当收发量变大时,内存占用会越来越大,在软件测试的时候甚至会达到数GB,最后想用数据库把这些收到的数据暂先存起来,然后通过对数据库的读取,分页获取历史报文。

首先大概展示一下我的主窗口页面

一、数据库的读写

设计的大概思路就是设一个报文类,里面存有一个报文中应有的一些参数

首先创建一个新的类DatabaseManager 存放数据库的初始化以及写入的方法,然后在方法中便可以直接调用。

using Microsoft.Data.Sqlite;
using System;
using UMI供电分析.Common;

public class DatabaseManager
{
    private readonly string _connectionString;// 声明一个只读字符串变量来保存数据库连接字符串
    //其中dPath存放的数据库的位置和名称
    public DatabaseManager(string dbPath)// 定义一个DatabaseManager类来管理数据库操作
    {
        _connectionString = $"Data Source={dbPath}";// 使用传入的数据库路径初始化连接字符串
        InitializeDatabase();
    }

    private void InitializeDatabase()
    {
        using (var connection = new SqliteConnection(_connectionString))
        {
            connection.Open();

            var command = connection.CreateCommand();
            command.CommandText =
            @"
                CREATE TABLE IF NOT EXISTS Packets (
                    Id INTEGER PRIMARY KEY AUTOINCREMENT,
                    Preamble TEXT,
                    DestinationAddress TEXT,
                    SourceAddress TEXT,
                    PayloadData TEXT,
                    FrameCheckSequence TEXT,
                    Timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
                );
            ";
            command.ExecuteNonQuery(); // 执行SQL命令
        }
    }

    public void InsertPacket(CustomPacket packet)
    {
        using (var connection = new SqliteConnection(_connectionString))
        {
            connection.Open();

            using (var transaction = connection.BeginTransaction())
            {
                var command = connection.CreateCommand();
                command.CommandText =
                @"
                    INSERT INTO Packets (Preamble, DestinationAddress, SourceAddress, PayloadData, FrameCheckSequence)
                    VALUES ($preamble, $destinationAddress, $sourceAddress, $payloadData, $frameCheckSequence);
                ";

                command.Parameters.AddWithValue("$preamble", packet.StringPremble);
                command.Parameters.AddWithValue("$destinationAddress", packet.StringDestinationAddress);
                command.Parameters.AddWithValue("$sourceAddress", packet.StringSourceAddress);
                command.Parameters.AddWithValue("$payloadData", packet.StringPayloadData);
                command.Parameters.AddWithValue("$frameCheckSequence", packet.StringFrameCheckSequence);

                command.ExecuteNonQuery();

                transaction.Commit();
            }
        }
    }
}

在C#中,using 语句用于确保在使用完资源后及时释放资源,以避免资源泄漏和提高性能。在数据库操作中,使用 using 语句可以确保数据库连接在使用完毕后被正确关闭和释放,从而避免连接资源被占用导致的性能问题或连接泄漏。

剩余的是一些数据库指令。

在接受报文的时候 若CRC校验正确,则添加加入数据库

二、分页处理数据

此处我在主窗口设置了加载更多报文 ,如若点击后,直接加载一个新的窗口,其中包括一个日期控件DatePacket,用于选择特定日子的报文

在这个VM中,我又设置了一个新的类来作为存储媒介接受报文,并在构造函数中创建了一个“媒介”对象

    public class PacketDataModel
        {
            public string StringPremble { get; set; }
            public string StringDestinationAddress { get; set; }
            public string StringSourceAddress { get; set; }
            public string StringPayloadData { get; set; }
            public string StringFrameCheckSequence { get; set; }
            public DateTime Timestamp { get; set; }
        }
    public HistoryPacketViewModel()//构造函数
        {
            Historypacket_db = new ObservableCollection<PacketDataModel>();
            LoadDataFromDatabase(1);
            //LoadUniqueDatesFromDatabase();
              SelectedDate = DateTime.Now; // 初始化为当前日期
        }

对上一页和下一页的代码设置

 public ICommand PacketLastPage => new DelegateCommand(
           LoadPreviousPage
        );

 private void LoadPreviousPage()
        {
            if (currentPage > 0)
            {
                Historypacket_db.Clear();
                currentPage--;
                LoadDataFromDatabase(currentPage);
            }
        }
  public ICommand PacketNextPage => new DelegateCommand(
           LoadNextPage
        );

  public void LoadNextPage()
        {
            Historypacket_db.Clear();
            currentPage++;
            LoadDataFromDatabase(currentPage);
        }

此处在命令执行一开始就先清空了数组代码,然后再执行了相关的一系列操作,目的是释放内存

接下来是日期选择的相关代码 

首先设置View的代码,主要是绑定内容

SelectedDate所绑定即为鼠标所选中的日期,接着再到VM中设定一下该变量属性,每次修改后,都要对VM中的变量进行修改,同时要更新一下新的页面加载

private DateTime selectedDate;
        public DateTime SelectedDate
        {
            get { return selectedDate; }
            set
            {
                SetProperty(ref selectedDate, value);
                LoadDataFromDatabase(1); // 根据选定的日期加载数据
            }
        }

接下来是页面加载代码

其中

  • ORDER BY Id DESC:按照Id列的值进行降序排序。
  • LIMIT {PageSize} OFFSET {page * PageSize}:限制返回的行数为PageSize,并根据当前页数page和PageSize来设置偏移量。
 private void LoadDataFromDatabase(int page)
        {
            string connectionString = "Data Source=YourDatabaseFilePath.db";// 建立数据库连接字符串
            using (var connection = new SqliteConnection(connectionString))// 使用SQLite连接对象,确保在作用域结束时自动释放资源
            {
                connection.Open();
                string countQuery = $"SELECT COUNT(*) FROM Packets WHERE DATE(Timestamp) = '{SelectedDate.ToString("yyyy-MM-dd")}'";
                string dataQuery = $"SELECT * FROM Packets WHERE DATE(Timestamp) = '{SelectedDate.ToString("yyyy-MM-dd")}' ORDER BY Id DESC LIMIT {PageSize} OFFSET {page * PageSize}";

                using (var countCommand = new SqliteCommand(countQuery, connection))
                {
                    totalPacketsCount = Convert.ToInt32(countCommand.ExecuteScalar());
                }

                // 计算总页数
                int totalPages = (totalPacketsCount + PageSize - 1) / PageSize;

                // 更新分页数据
                // 这里你需要根据实际情况处理页数溢出等问题
                currentPage = Math.Max(0, Math.Min(currentPage, totalPages - 1));

                using (var command = new SqliteCommand(dataQuery, connection))
                {
                    using (var reader = command.ExecuteReader())
                    {
                        ObservableCollection<PacketDataModel> newData = new ObservableCollection<PacketDataModel>();
                        while (reader.Read())
                        {
                            PacketDataModel packet = new PacketDataModel();

                            int stringPrembleIndex = reader.GetOrdinal("Preamble");
                            if (!reader.IsDBNull(stringPrembleIndex))
                            {
                                packet.StringPremble = reader.GetString(stringPrembleIndex);
                            }

                            int destinationAddressIndex = reader.GetOrdinal("DestinationAddress");
                            if (!reader.IsDBNull(destinationAddressIndex))
                            {
                                packet.StringDestinationAddress = reader.GetString(destinationAddressIndex);
                            }

                            int sourceAddressIndex = reader.GetOrdinal("SourceAddress");
                            if (!reader.IsDBNull(sourceAddressIndex))
                            {
                                packet.StringSourceAddress = reader.GetString(sourceAddressIndex);
                            }

                            int payloadDataIndex = reader.GetOrdinal("PayloadData");
                            if (!reader.IsDBNull(payloadDataIndex))
                            {
                                packet.StringPayloadData = reader.GetString(payloadDataIndex);
                            }

                            int frameCheckSequenceIndex = reader.GetOrdinal("FrameCheckSequence");
                            if (!reader.IsDBNull(frameCheckSequenceIndex))
                            {
                                packet.StringFrameCheckSequence = reader.GetString(frameCheckSequenceIndex);
                            }

                            int timestampIndex = reader.GetOrdinal("Timestamp");
                            if (!reader.IsDBNull(timestampIndex))
                            {
                                packet.Timestamp = reader.GetDateTime(timestampIndex);
                            }
                            Historypacket_db.Add(packet);
                        }

                    }
                }
            }
        }

其中两个 SQL 查询语句 countQuery 和 dataQuery,分别用于查询符合条件的记录总数和分页数据。

  • 15
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
WPF (Windows Presentation Foundation) 是一种用于创建 Windows 桌面应用程序的技术,而 SQLite 是一种嵌入式关系型数据库管理系统。结合 WPFSQLite 可以创建功能强大的桌面应用程序。 要在 WPF 中使用 SQLite,首先需要将 SQLite 数据库文件添加到项目中。可以使用 System.Data.SQLite 包来访问和操作 SQLite 数据库。可以通过 NuGet 包管理器来安装 System.Data.SQLite 包。 安装完成后,可以使用 SQLiteConnection 类来建立与数据库的连接,并使用 SQLiteCommand 类执行 SQL 查询和操作。可以使用 SQLiteDataReader 类来读取查询结果。 以下是一个简单的示例代码,演示了如何在 WPF 中使用 SQLite: ```csharp using System.Data.SQLite; // 建立连接 var connectionString = "Data Source=your_database_file.db"; using (var connection = new SQLiteConnection(connectionString)) { connection.Open(); // 执行查询 var sql = "SELECT * FROM your_table"; using (var command = new SQLiteCommand(sql, connection)) { using (var reader = command.ExecuteReader()) { while (reader.Read()) { // 处理每一行数据 var column1Value = reader["column1"].ToString(); var column2Value = reader["column2"].ToString(); // ... } } } // 执行插入、更新或删除操作 var sqlInsert = "INSERT INTO your_table (column1, column2) VALUES (@value1, @value2)"; using (var command = new SQLiteCommand(sqlInsert, connection)) { command.Parameters.AddWithValue("@value1", "value1"); command.Parameters.AddWithValue("@value2", "value2"); command.ExecuteNonQuery();

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值