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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 14:15:32