You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin Forms中SQLite已存在Boms表无法访问的问题咨询

SQLiteException: no such table: Boms in Xamarin Forms (with Dapper)

我来帮你拆解这个问题的核心原因,一步步解决它,同时对比官方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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:00:06