EF Core与SQLite实战:从零构建轻量级数据库应用
1. 为什么选择EF Core与SQLite这对黄金组合如果你正在开发一个需要本地数据存储的移动应用或桌面小工具SQLite绝对是你的首选数据库。这个只有几百KB的小家伙不需要任何服务器配置直接读写单个文件就能完成所有数据库操作。而EF Core作为.NET平台上的ORM框架能让你用面向对象的方式操作数据库彻底告别手写SQL语句的烦恼。我去年开发一个跨平台笔记应用时就用了这个组合。当时需要在Windows、macOS和Android三个平台上共享数据格式SQLite的跨平台特性完美解决了这个问题。EF Core则让我用同样的C#代码在不同平台上操作数据库开发效率直接翻倍。SQLite有三大不可替代的优势零配置部署只需要把数据库文件放在项目目录下不需要安装任何数据库服务极致轻量整个数据库引擎就封装在一个动态链接库里iOS应用打包后体积只增加300KBACID事务支持哪怕突然断电也不会损坏数据文件这点在移动设备上特别重要而EF Core 8.0带来的性能优化使得这个ORM在SQLite上的开销几乎可以忽略不计。我在Redmi Note 11上测试每秒能完成超过5000次的简单查询操作对于大多数应用场景都绰绰有余。2. 五分钟快速搭建开发环境2.1 安装必备NuGet包打开Visual Studio新建一个控制台项目在包管理器控制台执行以下命令Install-Package Microsoft.EntityFrameworkCore.Sqlite -Version 8.0.2这个命令会同时安装EF Core核心包和SQLite提供程序。如果你喜欢用.NET CLI也可以这样dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 8.0.2注意建议固定版本号避免自动升级到可能不兼容的新版本。我在去年就踩过坑自动升级到7.0时部分API发生了变更。2.2 准备数据库文件在项目根目录下新建一个Data文件夹里面创建空的app.db文件。用文本编辑器打开.csproj文件确保包含类似配置ItemGroup None UpdateData\app.db CopyToOutputDirectoryPreserveNewest/CopyToOutputDirectory /None /ItemGroup这样每次编译时都会自动把数据库文件复制到输出目录。我在初期开发时经常忘记这个配置导致调试时修改的数据在下次运行时神秘消失。3. 设计你的第一个数据模型3.1 定义实体类假设我们要开发一个简单的待办事项应用先创建TodoItem类public class TodoItem { public int Id { get; set; } [Required] [MaxLength(100)] public string Title { get; set; } public string Description { get; set; } public bool IsCompleted { get; set; } public DateTime CreatedTime { get; set; } DateTime.Now; public DateTime? DueTime { get; set; } }这里用到了数据注解[Required]确保标题不能为null[MaxLength(100)]限制标题长度DateTime?表示可空的时间类型3.2 创建数据库上下文新建AppDbContext.cs文件public class AppDbContext : DbContext { public DbSetTodoItem TodoItems { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlite(Data SourceData/app.db); } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.EntityTodoItem() .HasIndex(t t.Title); } }几个关键点DbSetTodoItem表示数据库中的表连接字符串只需要指定文件路径在OnModelCreating中可以为标题字段添加索引提升查询速度4. 数据库迁移与初始化4.1 安装EF Core工具在包管理器控制台运行dotnet tool install --global dotnet-ef dotnet add package Microsoft.EntityFrameworkCore.Design4.2 创建并应用迁移执行以下命令dotnet ef migrations add InitialCreate dotnet ef database update这会在项目中生成Migrations文件夹里面包含迁移代码文件。我在团队协作时遇到过迁移冲突问题建议把迁移文件也纳入版本控制。4.3 初始化测试数据修改AppDbContext重写OnModelCreatingprotected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.EntityTodoItem().HasData( new TodoItem { Id 1, Title 学习EF Core, IsCompleted false }, new TodoItem { Id 2, Title 写博客, IsCompleted true } ); }然后再次运行dotnet ef database update数据库就会自动填充测试数据。这个功能在开发初期特别有用。5. 实现CRUD操作5.1 添加新条目using var db new AppDbContext(); var newItem new TodoItem { Title 购买食材, Description 牛奶、鸡蛋、面包, DueTime DateTime.Today.AddDays(1) }; db.TodoItems.Add(newItem); await db.SaveChangesAsync();实战经验一定要用using确保DbContext及时释放我在生产环境就遇到过连接泄露导致应用崩溃的问题。5.2 查询数据// 获取未完成项 var pendingItems await db.TodoItems .Where(t !t.IsCompleted) .OrderBy(t t.DueTime) .ToListAsync(); // 模糊搜索 var searchResults await db.TodoItems .Where(t EF.Functions.Like(t.Title, %购物%)) .ToListAsync();EF Core 8.0对SQLite的全文搜索支持更好了但需要额外配置modelBuilder.EntityTodoItem() .HasIndex(t t.Title) .HasMethod(FTS);5.3 更新数据var item await db.TodoItems.FindAsync(1); if (item ! null) { item.IsCompleted true; item.Description 已完成; await db.SaveChangesAsync(); }5.4 删除数据var item new TodoItem { Id 2 }; db.Entry(item).State EntityState.Deleted; await db.SaveChangesAsync();这种删除方式只需要知道ID不需要先查询整个对象。6. 高级技巧与性能优化6.1 批量操作EF Core 8.0新增了批量更新/删除功能await db.TodoItems .Where(t t.DueTime DateTime.Today) .ExecuteUpdateAsync(t t.SetProperty( p p.Description, p p.Description 已过期));这个操作只会生成一条SQL语句效率比先查询再逐个修改高得多。6.2 事务处理using var transaction await db.Database.BeginTransactionAsync(); try { // 多个操作 await db.SaveChangesAsync(); await transaction.CommitAsync(); } catch { await transaction.RollbackAsync(); throw; }对于需要原子性保证的操作一定要使用显式事务。6.3 连接池配置在连接字符串中添加Data SourceData/app.db;PoolingFalse禁用连接池可以避免在移动设备上出现文件锁定问题。我在Xamarin项目中就遇到过应用退出后无法立即删除数据库文件的情况。7. 调试与问题排查7.1 查看生成的SQL在AppDbContext中添加protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlite(Data SourceData/app.db) .LogTo(Console.WriteLine, LogLevel.Information); }这样所有SQL语句都会输出到控制台。我在优化查询性能时这个功能帮了大忙。7.2 处理并发冲突给实体类添加[Timestamp] public byte[] RowVersion { get; set; }然后在更新时捕获DbUpdateConcurrencyException异常。7.3 数据库文件位置问题在移动开发中正确的数据库路径应该是var dbPath Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), app.db);这样能确保应用卸载时数据库文件也被清除。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2463423.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!