Xamarin Forms中SQLite已存在Boms表无法访问的问题咨询
我来帮你拆解这个问题的核心原因,一步步解决它,同时对比官方Todo示例的差异:
核心问题根源
你遇到的no such table: Boms错误,本质上是数据库里根本没有创建Boms表,再加上你的实体类包含SQLite.NET不支持的导航属性,可能导致表创建逻辑执行失败(如果你完全没加创建表的代码,那就是表从未被初始化)。
另外,Dapper在这里只是负责数据查询,它不负责表结构的创建,所以和Dapper本身无关,问题出在SQLite.NET的使用逻辑上。
分步解决方案
1. 必须添加表创建逻辑
你的StockDatabase构造函数只初始化了数据库连接,但没有创建Boms表。SQLite不会自动为实体类生成表,必须显式调用创建表的方法。
修改构造函数,添加表创建代码:
public StockDatabase() { var path = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "FuelStockApp2.db3"); Console.WriteLine("Opening Database dbPath: " + path); database = new SQLiteAsyncConnection(path); // 关键:创建Boms表(如果已存在则不会重复创建) // 注意:构造函数不能用await,所以用Wait();如果担心死锁,建议在App启动时异步初始化数据库 database.CreateTableAsync<Boms>().Wait(); }
更优雅的做法是在App.xaml.cs的OnStart方法里异步初始化:
protected override async void OnStart() { var db = new StockDatabase(); await db.database.CreateTableAsync<Boms>(); // 其他初始化逻辑 }
2. 修正实体类的导航属性
SQLite.NET是轻量级ORM,不支持直接存储List<T>这类复杂导航属性,这些属性会导致SQLite尝试创建不支持的列类型,进而可能导致表创建失败。你需要用[Ignore]标记告诉SQLite忽略这些属性:
首先引用SQLite.NET的命名空间using SQLite;,然后修改实体类:
namespace StockAppDal.Models { public class Boms { public enum BomStatus { InActive = 0, Listed =1, Scanned = 2, Completed = 3 } public BomStatus Status { get; set; } public long BomId { get; set; } public long BOMLineID { get; set; } public long StockItemID { get; set; } public string BOMLineTypeID { get; set; } public decimal? Quantity { get; set; } public long UnitID { get; set; } public decimal? MultipleOfBaseUnit { get; set; } public string Code { get; set; } public string Name { get; set; } public string Barcode { get; set; } public long ProductGroupID { get; set; } public string ProductGroupCode { get; set; } public bool Scanned { get; set; } [Ignore] // 标记忽略这个导航属性 public List<Warehouse> Warehouses { get; set; } [Ignore] // 标记忽略这个导航属性 public List<BomDetail> Lines { get; set; } public override string ToString() { return Code; } } }
如果需要持久化Warehouses和Lines的数据,你需要单独创建对应的Warehouse和BomDetail实体类与表,并通过外键关联到Boms的BomId。
3. 关于Dapper的说明
Dapper不需要对实体类做特殊标记(比如属性注解),它通过属性名和数据库列名的匹配来映射数据。只要你用SQLite.NET创建了正确的Boms表结构,Dapper就可以正常查询该表。
为什么官方Todo示例可以正常运行?
官方Todo示例的核心差异有两点:
- 示例中的
TodoItem是简单实体,没有复杂的导航属性,SQLite.NET可以轻松创建对应的表; - 示例明确调用了
CreateTableAsync<TodoItem>来确保表存在,比如在TodoItemDatabase的初始化逻辑中,会异步创建TodoItem表,所以查询时不会出现表不存在的错误。
内容的提问来源于stack exchange,提问作者dotnetdevcsharp

