Android SQLite:对象作为另一对象属性时遇NotSupportedException问题求解
问题与解决方案:SQLite-net 中 Course 与 Assessment 关联报错处理
问题描述
将Course类的部分属性整合到Assessment类后,在Course类中添加了public Assessment OA和public Assessment PA两个属性,初始化数据库时抛出错误:
System.NotSupportedException: 'Don't know about C971.Models.Assessment'
同时疑问当前实现方式是否有误,是否应该用外键关联独立表中的Assessment对象。
原因分析
SQLite-net是轻量级ORM框架,默认不支持直接在实体类中嵌套另一个实体对象作为属性,它无法将嵌套对象直接映射到数据库的表结构中,因此会抛出无法识别嵌套类的异常。这种场景下,使用外键关联独立表的方式才是符合关系型数据库设计的正确方案。
修正方案
1. 修改Assessment类,添加外键与类型标识
为了区分同一个Course下的OA和PA两种Assessment,给Assessment类添加关联Course的外键字段,以及标识类型的字段:
public class Assessment { [PrimaryKey, AutoIncrement] public int id { get; set; } // 关联Course的外键 public int CourseId { get; set; } // 标识是OA还是PA public AssessmentType Type { get; set; } public string name { get; set; } = string.Empty; public DateTime startDate { get; set; } public DateTime endDate { get; set; } public DateTime dueDate { get; set; } public string info { get; set; } = string.Empty; public bool startAlert { get; set; } = false; public bool endAlert { get; set; } = false; } // 定义Assessment类型枚举 public enum AssessmentType { OA, PA }
2. 修改Course类,移除嵌套的Assessment属性
删除Course类中直接嵌套的Assessment对象,改为通过外键查询获取对应的数据:
public class Course { [PrimaryKey, AutoIncrement] public int id { get; set; } public int termId { get; set; } public DateTime startDate { get; set; } public DateTime endDate { get; set; } public DateTime dueDate { get; set; } public courseStatus status { get; set; } = courseStatus.planned; public string name { get; set; } = "Placeholder Name"; public string notes { get; set; } = string.Empty; public bool alertStartDate { get; set; } = false; public bool alertEndDate { get; set; } = false; // 保留标记字段,方便判断是否已设置OA/PA public bool isSetOA { get; set; } = false; public bool isSetPA { get; set; } = false; public string courseInfo { get; set; } = string.Empty; public string instructorName { get; set; } = string.Empty; public string instructorPhone { get; set; } = string.Empty; public string instructorEmail { get; set; } = string.Empty; public enum courseStatus { inProgress, completed, dropped, planned } }
3. 调整数据库初始化,开启外键约束
在数据库初始化时添加外键约束开启的语句,确保关联关系生效:
private static SQLiteAsyncConnection? Database; static async Task Init() { Debug.WriteLine("TermTrackerDB.Init start"); try { if (Database is not null) return; Database = new SQLiteAsyncConnection(Constants.DatabasePath, Constants.Flags); // 开启SQLite外键约束 await Database.ExecuteAsync("PRAGMA foreign_keys = ON"); await Database.CreateTableAsync<Assessment>(); await Database.CreateTableAsync<Course>(); await Database.CreateTableAsync<Term>(); } catch (Exception e) { Debug.WriteLine($"Try Catch: TermTrackerDB Init; Exception: {0}", e); throw; } }
4. 业务层查询Course对应的OA/PA
编写查询方法,根据CourseId和AssessmentType获取对应的Assessment:
// 获取Course对应的OA public async Task<Assessment?> GetCourseOA(int courseId) { return await Database.Table<Assessment>() .FirstOrDefaultAsync(a => a.CourseId == courseId && a.Type == AssessmentType.OA); } // 获取Course对应的PA public async Task<Assessment?> GetCoursePA(int courseId) { return await Database.Table<Assessment>() .FirstOrDefaultAsync(a => a.CourseId == courseId && a.Type == AssessmentType.PA); }
总结
原实现方式的核心问题是试图让SQLite-net支持对象嵌套映射,这超出了它的默认能力范围。改用外键关联独立表的方式,既符合关系型数据库的设计规范,也能完美适配SQLite-net的功能特性。
内容的提问来源于stack exchange,提问作者Dylan Blackhorse-von Jess
相关产品推荐
相关产品推荐

