FreeSql + Sqlite实战:WPF应用中的CRUD操作全解析(附完整代码)

张开发
2026/4/18 0:07:59 15 分钟阅读

分享文章

FreeSql + Sqlite实战:WPF应用中的CRUD操作全解析(附完整代码)
FreeSql Sqlite实战WPF应用中的CRUD操作全解析附完整代码在.NET生态中WPF作为成熟的桌面应用框架与轻量级数据库Sqlite的结合为开发者提供了快速构建本地数据存储应用的理想方案。而FreeSql作为.NET平台下的高效ORM工具进一步简化了数据操作流程。本文将深入探讨如何在.NET 8环境下通过Prism框架实现MVVM模式完成从数据库配置到完整CRUD功能的实战开发。1. 环境搭建与项目初始化1.1 开发环境配置首先确保已安装以下工具和组件Visual Studio 202217.6版本.NET 8 SDKNuGet包管理器创建WPF项目时需添加以下关键NuGet包dotnet add package FreeSql.Provider.Sqlite dotnet add package Prism.DryIoc dotnet add package HandyControl1.2 项目结构设计推荐采用分层架构组织代码FreeSqlDemo/ ├── DAL/ # 数据访问层 │ └── DB.cs # FreeSql实例管理 ├── Models/ # 数据模型 │ └── Blog.cs # 实体类定义 ├── ViewModels/ # 视图模型 │ └── MainWindowViewModel.cs ├── Views/ # 视图层 │ └── MainWindow.xaml └── App.xaml # 应用入口2. FreeSql与Sqlite深度集成2.1 数据库连接配置在DB.cs中配置FreeSql实例时有几个关键参数需要注意public static IFreeSql Sqlite new FreeSqlBuilder() .UseConnectionString(DataType.Sqlite, Data SourceDB\demo.db;Poolingtrue;Min Pool Size1) .UseAutoSyncStructure(true) // 自动同步实体结构到数据库 .UseMonitorCommand(cmd Debug.WriteLine(cmd.CommandText)) // SQL日志 .Build();提示生产环境中建议将连接字符串存储在配置文件中而非硬编码2.2 实体模型定义最佳实践定义数据模型时FreeSql提供了丰富的特性注解[Table(Name blogs)] // 指定表名 public class Blog { [Column(IsIdentity true, IsPrimary true)] public int Id { get; set; } [Column(StringLength 500)] public string Url { get; set; } [Column(DbType INT DEFAULT 0)] public int Rating { get; set; } [Column(ServerTime DateTimeKind.Utc)] public DateTime CreateTime { get; set; } }3. MVVM模式下的CRUD实现3.1 增删改查完整示例在视图模型中实现完整的CRUD操作public class MainWindowViewModel : BindableBase { private string _status; public string Status { get _status; set SetProperty(ref _status, value); } // 插入数据 public DelegateCommand InsertCommand new(() { var blog new Blog { Url https://example.com }; var id DB.Sqlite.Insert(blog).ExecuteIdentity(); Status $插入成功ID: {id}; }); // 条件查询 public DelegateCommand QueryCommand new(() { var blogs DB.Sqlite.SelectBlog() .Where(b b.Rating 3) .OrderByDescending(b b.CreateTime) .ToList(); Status $查询到 {blogs.Count} 条记录; }); // 批量更新 public DelegateCommand UpdateCommand new(() { var affected DB.Sqlite.UpdateBlog() .Set(b b.Rating, 5) .Where(b b.Url.Contains(example)) .ExecuteAffrows(); Status $更新了 {affected} 条记录; }); // 软删除模式 public DelegateCommand DeleteCommand new(() { var affected DB.Sqlite.DeleteBlog() .Where(b b.Id 1) .ExecuteAffrows(); Status $删除了 {affected} 条记录; }); }3.2 高级查询技巧FreeSql提供了丰富的查询API// 分页查询 var pagedList DB.Sqlite.SelectBlog() .Where(b b.Rating 0) .Count(out var total) .Page(1, 20) .ToList(); // 联表查询 var joinedData DB.Sqlite.SelectBlog() .LeftJoinComment((b, c) b.Id c.BlogId) .ToList((b, c) new { b.Url, c.Content }); // 原生SQL查询 var rawQuery DB.Sqlite.Ado.QueryBlog( SELECT * FROM blogs WHERE rating rating, new { rating 3 });4. 性能优化与实战技巧4.1 批量操作优化对于大量数据操作使用批量处理显著提升性能// 批量插入事务自动提交 var inserted DB.Sqlite.Insert(Enumerable.Range(1, 1000) .Select(i new Blog { Url $blog_{i}.com })) .ExecuteAffrows(); // 批量更新 var updated DB.Sqlite.UpdateBlog() .Set(b b.Rating, b b.Rating 1) .Where(b b.CreateTime DateTime.Today) .ExecuteAffrows();4.2 事务处理模式FreeSql支持多种事务管理方式// 显式事务 using (var uow DB.Sqlite.CreateUnitOfWork()) { try { var repo uow.GetRepositoryBlog(); repo.Insert(new Blog { Url trans1.com }); repo.Update(new Blog { Id 1, Rating 5 }); uow.Commit(); } catch { uow.Rollback(); throw; } } // 工作单元模式 var affrows DB.Sqlite.Transaction(() { var blog DB.Sqlite.Insert(new Blog { Url trans2.com }) .ExecuteInserted(); DB.Sqlite.UpdateComment() .Set(c c.IsApproved, true) .Where(c c.BlogId blog[0].Id) .ExecuteAffrows(); });4.3 缓存策略实现FreeSql内置二级缓存支持// 启用全局缓存 var sqlite new FreeSqlBuilder() .UseConnectionString(DataType.Sqlite, ...) .UseLazyLoading(true) .UseNoneCommandParameter(true) .UseCache(typeof(MyCacheProvider)) // 自定义缓存实现 .Build(); // 查询时指定缓存 var cachedData DB.Sqlite.SelectBlog() .Where(b b.Rating 3) .WithCache(TimeSpan.FromMinutes(5)) .ToList();5. 异常处理与调试技巧5.1 常见问题排查开发过程中可能遇到的典型问题及解决方案问题现象可能原因解决方案连接失败数据库文件路径错误使用绝对路径或检查文件权限表不存在AutoSyncStructure未启用设置.UseAutoSyncStructure(true)性能低下未启用连接池连接字符串添加Poolingtrue5.2 日志记录配置通过事件监听实现全面的SQL日志DB.Sqlite.Aop.CurdAfter (s, e) { Debug.WriteLine($SQL: {e.Sql}\nParams: {string.Join(,, e.Parses)}); if (e.Exception ! null) Logger.Error(e.Exception, 执行SQL出错); }; DB.Sqlite.Aop.SyncStructureAfter (s, e) { if (e.Sql.NotNull()) Debug.WriteLine($同步结构: {e.Sql}); };5.3 单元测试策略为数据访问层编写可靠的单元测试[TestClass] public class BlogRepositoryTests { private IFreeSql _testSqlite; [TestInitialize] public void Setup() { _testSqlite new FreeSqlBuilder() .UseConnectionString(DataType.Sqlite, Data Source:memory:) .UseAutoSyncStructure(true) .Build(); } [TestMethod] public void InsertBlog_ShouldReturnId() { var repo _testSqlite.GetRepositoryBlog(); var blog new Blog { Url test.com }; var id repo.Insert(blog); Assert.IsTrue(id 0); var saved repo.Select.Where(b b.Id id).First(); Assert.AreEqual(test.com, saved.Url); } }在实际项目开发中我们发现FreeSql的Lambda表达式解析非常稳定但在处理复杂嵌套查询时适当拆分查询步骤可以提高代码可读性。对于高频访问的热点数据建议结合内存缓存减少数据库压力。

更多文章