news 2026/3/6 4:25:51

整合 Sugar ORM 连接 SQLite 数据库到 WPF 折线图项目

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
整合 Sugar ORM 连接 SQLite 数据库到 WPF 折线图项目

一、核心目标

在原有 WPF 折线图项目基础上,通过Sugar ORM连接 SQLite 数据库,实现:

  1. 从 SQLite 读取历史销量数据渲染折线图

  2. 追加数据时同时写入数据库,实现数据持久化

二、前置准备

1. 安装依赖包

通过 NuGet 安装以下包:

包名作用
SqlSugarCoreSugar ORM 核心(支持 SQLite)
System.Data.SQLiteSQLite 数据库驱动
Microsoft.Data.Sqlite可选(替代 System.Data.SQLite)

2. SQLite 数据库准备

(1)创建数据库文件

在项目根目录创建SalesData.db文件(也可让 Sugar 自动创建)。

(2)创建销量表

定义销量实体类,Sugar 会自动生成数据表:

using SqlSugar; using System; ​ namespace LineChart2.Model { /// <summary> /// 销量数据表实体 /// </summary> [SugarTable("SalesRecord")] public class SalesRecord { /// <summary> /// 主键(自增) /// </summary> [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] public int Id { get; set; } ​ /// <summary> /// 年份(2023/2024) /// </summary> [SugarColumn(ColumnName = "Year")] public int SalesYear { get; set; } ​ /// <summary> /// 月份(1-12) /// </summary> public int Month { get; set; } ​ /// <summary> /// 销量数值 /// </summary> public double SalesValue { get; set; } ​ /// <summary> /// 创建时间 /// </summary> public DateTime CreateTime { get; set; } = DateTime.Now; } }

三、Sugar ORM 初始化配置

创建数据库帮助类,封装 Sugar 连接和操作:

using SqlSugar; using LineChart2.Model; using System; using System.IO; ​ namespace LineChart2.Helper { public class DbHelper { // Sugar数据库连接实例(单例) public static SqlSugarClient Db { get; private set; } ​ static DbHelper() { // 初始化连接 InitDb(); } ​ /// <summary> /// 初始化SQLite连接 /// </summary> private static void InitDb() { // 获取数据库文件路径(项目根目录) string dbPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SalesData.db"); ​ Db = new SqlSugarClient(new ConnectionConfig { ConnectionString = $"Data Source={dbPath};", // SQLite连接字符串 DbType = DbType.Sqlite, // 数据库类型 IsAutoCloseConnection = true, // 自动关闭连接 InitKeyType = InitKeyType.Attribute // 从特性读取主键/自增配置 }); ​ // 初始化数据表(不存在则创建) Db.CodeFirst.InitTables(typeof(SalesRecord)); ​ // 开启日志(调试用,生产可关闭) Db.Aop.OnLogExecuting = (sql, pars) => { Console.WriteLine($"SQL:{sql} \r\n参数:{string.Join(",", pars.Select(p => p.ParameterName + "=" + p.Value))}"); }; } ​ #region 销量数据操作封装 /// <summary> /// 批量插入销量数据 /// </summary> public static void BatchInsertSalesData(SalesRecord[] records) { Db.Insertable(records).ExecuteCommand(); } ​ /// <summary> /// 插入单条销量数据 /// </summary> public static int InsertSalesData(SalesRecord record) { return Db.Insertable(record).ExecuteReturnIdentity(); } ​ /// <summary> /// 根据年份查询销量数据 /// </summary> public static List<SalesRecord> GetSalesDataByYear(int year) { return Db.Queryable<SalesRecord>() .Where(r => r.SalesYear == year) .OrderBy(r => r.Month) .ToList(); } ​ /// <summary> /// 查询所有年份的销量数据 /// </summary> public static List<SalesRecord> GetAllSalesData() { return Db.Queryable<SalesRecord>() .OrderBy(r => r.SalesYear) .ThenBy(r => r.Month) .ToList(); } #endregion } }

四、修改折线图控件,整合数据库操作

1. 重构 UCLineChart.xaml.cs

替换原有硬编码数据,改为从数据库读取 / 写入:

using LiveCharts; using LiveCharts.Defaults; using LiveCharts.Wpf; using LineChart2.Helper; using LineChart2.Model; using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; ​ namespace LineChart2 { public partial class UCLineChart : UserControl { public SeriesCollection SeriesCollection { get; set; } public string[] Labels { get; set; } public Func<double, string> YFormatter { get; set; } ​ // 模拟销量数据 private readonly Random _random = new Random(); // 当前最大月份(用于追加数据) private int _currentMaxMonth = 5; ​ public UCLineChart() { InitializeComponent(); ​ // 初始化图表数据(优先从数据库读取) InitChartDataFromDb(); ​ // Y轴格式化(显示整数) YFormatter = value => $"{value:N0}"; ​ DataContext = this; } ​ /// <summary> /// 从数据库初始化图表数据 /// </summary> private void InitChartDataFromDb() { SeriesCollection = new SeriesCollection(); ​ // 1. 查询所有销量数据 var allSalesData = DbHelper.GetAllSalesData(); ​ // 2. 如果数据库无数据,初始化默认数据并写入数据库 if (!allSalesData.Any()) { InitDefaultDataAndWriteToDb(); allSalesData = DbHelper.GetAllSalesData(); } ​ // 3. 按年份分组构建折线系列 var groupedData = allSalesData.GroupBy(r => r.SalesYear); foreach (var group in groupedData) { int year = group.Key; var values = group.OrderBy(r => r.Month).Select(r => r.SalesValue).ToList(); ​ // 创建折线系列 LineSeries series = new LineSeries { Title = $"{year}年", Values = new ChartValues<double>(values), LineSmoothness = 0.3, StrokeThickness = 2, PointGeometrySize = 8 }; ​ // 不同年份设置不同颜色 series.Stroke = year == 2024 ? Brushes.DodgerBlue : Brushes.OrangeRed; series.PointForeground = year == 2024 ? Brushes.DodgerBlue : Brushes.OrangeRed; series.PointGeometry = year == 2024 ? DefaultGeometries.Circle : DefaultGeometries.Square; ​ SeriesCollection.Add(series); } ​ // 4. 构建X轴标签(1-当前最大月份) _currentMaxMonth = allSalesData.Max(r => r.Month); Labels = Enumerable.Range(1, _currentMaxMonth).Select(m => $"{m}月").ToArray(); } ​ /// <summary> /// 初始化默认数据并写入数据库 /// </summary> private void InitDefaultDataAndWriteToDb() { List<SalesRecord> defaultData = new List<SalesRecord>(); ​ // 2024年1-5月数据 double[] sales2024 = { 120, 150, 110, 180, 160 }; for (int i = 0; i < sales2024.Length; i++) { defaultData.Add(new SalesRecord { SalesYear = 2024, Month = i + 1, SalesValue = sales2024[i] }); } ​ // 2023年1-5月数据 double[] sales2023 = { 100, 130, 140, 150, 130 }; for (int i = 0; i < sales2023.Length; i++) { defaultData.Add(new SalesRecord { SalesYear = 2023, Month = i + 1, SalesValue = sales2023[i] }); } ​ // 批量写入数据库 DbHelper.BatchInsertSalesData(defaultData.ToArray()); } ​ // 追加数据按钮点击事件 private void BtnAddData_Click(object sender, RoutedEventArgs e) { // 1. 月份+1 _currentMaxMonth++; int newMonth = _currentMaxMonth; ​ // 2. 生成随机销量(100-200) double sales2024 = _random.Next(100, 200); double sales2023 = _random.Next(100, 200); ​ // 3. 写入数据库 DbHelper.InsertSalesData(new SalesRecord { SalesYear = 2024, Month = newMonth, SalesValue = sales2024 }); DbHelper.InsertSalesData(new SalesRecord { SalesYear = 2023, Month = newMonth, SalesValue = sales2023 }); ​ // 4. 追加数据点到图表 SeriesCollection[0].Values.Add(sales2024); SeriesCollection[1].Values.Add(sales2023); ​ // 5. 更新X轴标签 Array.Resize(ref Labels, Labels.Length + 1); Labels[Labels.Length - 1] = $"{newMonth}月"; ​ // 6. 刷新绑定(触发UI更新) chart.AxisX[0].Labels = Labels; ​ // 更新按钮文本(追加7月、8月...) (sender as Button).Content = $"追加{newMonth + 1}月数据"; } } }

2. 修复原代码 Bug

原代码中Labels数组扩容时使用了错误的方法,已替换为Array.Resize

// 错误写法 // Labels[Labels.Length - 1] = "6月"; ​ // 正确写法 Array.Resize(ref Labels, Labels.Length + 1); Labels[Labels.Length - 1] = $"{newMonth}月";

五、关键功能说明

1. 数据库初始化逻辑

  • 首次运行时,若数据库无数据,自动插入 2023/2024 年 1-5 月默认数据

  • 后续运行时,从数据库读取数据渲染图表,保证数据持久化

2. 数据追加逻辑

  • 点击按钮时,生成随机销量数据并写入数据库

  • 同时更新图表数据,实现 “数据库 + UI” 双向同步

  • 按钮文本动态更新(追加 6 月→追加 7 月→...)

3. Sugar ORM 核心操作

操作核心代码示例
初始化连接new SqlSugarClient(new ConnectionConfig { ... })
自动建表Db.CodeFirst.InitTables(typeof(SalesRecord))
批量插入Db.Insertable(records).ExecuteCommand()
条件查询Db.Queryable<SalesRecord>().Where(r => r.SalesYear == year).ToList()
排序查询OrderBy(r => r.Month)

六、运行验证

  1. 启动项目,首次运行会自动创建SalesData.db文件,并插入默认数据

  2. 图表会显示 2023/2024 年 1-5 月销量折线

  3. 点击 “追加 6 月数据” 按钮:

    • 数据库会新增 2023/2024 年 6 月销量记录

    • 图表自动追加 6 月数据点,X 轴标签更新为 “6 月”

    • 按钮文本变为 “追加 7 月数据”,重复点击可持续追加

七、扩展优化建议

1. 异常处理

添加 try-catch 捕获数据库操作异常:

try { DbHelper.InsertSalesData(new SalesRecord { ... }); } catch (Exception ex) { MessageBox.Show($"数据写入失败:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); }

2. 分页查询(大数据量)

若销量数据量大,可分页读取:

// 分页查询2024年数据(第1页,每页10条) var pageData = Db.Queryable<SalesRecord>() .Where(r => r.SalesYear == 2024) .OrderBy(r => r.Month) .ToPageList(1, 10);

3. 数据更新 / 删除

扩展 DbHelper 添加更新 / 删除方法:

/// <summary> /// 更新销量数据 /// </summary> public static bool UpdateSalesData(SalesRecord record) { return Db.Updateable(record).ExecuteCommand() > 0; } ​ /// <summary> /// 删除指定月份数据 /// </summary> public static bool DeleteSalesData(int year, int month) { return Db.Deleteable<SalesRecord>() .Where(r => r.SalesYear == year && r.Month == month) .ExecuteCommand() > 0; }

4. 多表关联(进阶)

若需要关联其他表(如产品表),可使用 Sugar 的联表查询:

// 关联产品表查询销量 var joinData = Db.Queryable<SalesRecord, Product>((s, p) => new JoinQueryInfos( JoinType.Inner, s.ProductId == p.Id)) .Select((s, p) => new { s.Month, s.SalesValue, p.ProductName }) .ToList();

八、项目结构梳理

LineChart2/ ├─ Helper/ │ └─ DbHelper.cs // Sugar ORM数据库操作封装 ├─ Model/ │ └─ SalesRecord.cs // 销量数据实体类 ├─ UCLineChart.xaml // 折线图用户控件XAML ├─ UCLineChart.xaml.cs // 折线图逻辑(整合数据库) ├─ MainWindow.xaml // 主窗口 └─ SalesData.db // SQLite数据库文件(运行后生成)

通过以上改造,原有的 WPF 折线图项目实现了与 SQLite 数据库的无缝整合,数据不再局限于内存,而是通过 Sugar ORM 实现了持久化存储和动态读写。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/3 18:06:23

如何用PHP构建可扩展的灯光控制系统?这套架构已被头部厂商采用

第一章&#xff1a;PHP 智能家居 灯光控制接口 在现代智能家居系统中&#xff0c;灯光控制是核心功能之一。通过 PHP 构建的后端接口&#xff0c;可以实现对智能灯具的状态管理、远程开关以及亮度调节等功能。该接口通常基于 RESTful 风格设计&#xff0c;与前端应用或移动客户…

作者头像 李华
网站建设 2026/3/5 8:28:30

无需编程基础!科哥开发的HeyGem系统让AI数字人触手可及

无需编程基础&#xff01;科哥开发的HeyGem系统让AI数字人触手可及 在短视频内容爆炸式增长的今天&#xff0c;企业需要快速制作多语种宣传视频&#xff0c;教育机构希望打造AI讲师课程&#xff0c;自媒体人则渴望拥有专属虚拟IP。但传统数字人生成方案动辄依赖Python脚本、命令…

作者头像 李华
网站建设 2026/2/26 19:46:55

前端新手必看:用事件委托轻松搞定动态元素交互(附实战技巧)

前端新手必看&#xff1a;用事件委托轻松搞定动态元素交互&#xff08;附实战技巧&#xff09;前端新手必看&#xff1a;用事件委托轻松搞定动态元素交互&#xff08;附实战技巧&#xff09;引言&#xff1a;为什么你总在动态元素上绑不住点击&#xff1f;事件委托到底是个啥&a…

作者头像 李华
网站建设 2026/2/27 19:30:36

格鲁吉亚语高加索登山指南:向导数字人介绍徒步路线

格鲁吉亚语高加索登山指南&#xff1a;向导数字人介绍徒步路线 —— HeyGem 数字人视频生成系统技术解析 在格鲁吉亚的高加索山脉深处&#xff0c;一条古老的徒步线路正悄然“苏醒”。镜头前&#xff0c;一位身着传统服饰的登山向导面带微笑&#xff0c;用流利的格鲁吉亚语讲述…

作者头像 李华
网站建设 2026/3/2 6:13:05

确保Amazon S3对象私有的最佳解决方案:预防性控制与强制执行

在云计算时代&#xff0c;数据安全是企业运营的核心。对于依赖Amazon S3存储敏感对象&#xff08;如图片&#xff09;的公司而言&#xff0c;避免意外公开暴露是至关重要的安全要求。本文针对一家图片托管公司的需求——确保整个AWS账户中所有S3对象保持私有&#xff0c;分析并…

作者头像 李华
网站建设 2026/3/2 3:12:33

【C#扩展性设计黄金法则】:资深架构师20年经验总结的6个关键模式

第一章&#xff1a;C#企业系统扩展性设计的核心挑战在构建大型企业级应用时&#xff0c;C#开发者常面临系统扩展性不足的困境。随着业务增长&#xff0c;原本稳定的架构可能因模块耦合度高、依赖固化而难以横向拓展。如何在不重构整体结构的前提下实现功能快速迭代&#xff0c;…

作者头像 李华