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

Xamarin Forms中SQLite跨模型数据访问异常求助

Xamarin Forms SQLite关联数据存储与读取问题解决方案

问题描述

我在使用SQLite开发Xamarin Forms项目时遇到以下问题:

  • 在新增Item页面创建Item实例并关联Priority模型,点击保存后调试时能获取到包含Priority的完整数据
  • 但SQLite数据库中Item表的ItemPriority字段仅显示{CrudTasks.Models.Priority}
  • 在列表页访问该关联数据时无响应

相关代码

保存Item的方法

private async void ExecuteSaveItemsCommand()
{
    try
    {
        Item itemSaved = new Item
        {
            Name = NameSave,
            Description = DescriptionSave,
            ItemPriority = new Priority()
            {
                PriorityName = PrioritySave,
                PriorityColor = "#ccc"
            }
        };

        _itemsService.InsertItem(itemSaved);
        ExecuteBackProductPageCommand();
    }
    catch (Exception ex)
    {
        await Shell.Current.DisplayAlert("Error", ex.Message, "OK");
    }
}

Item模型

namespace CrudTarefas.Models
{
    [Table("Items")]
    public class Item
    {
        [PrimaryKey, AutoIncrement] 
        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }

        [ManyToOne]
        public Priority ItemPriority { get; set; }
    }
}

Priority模型

namespace CrudTarefas.Models
{
    [Table("Priorities")]
    public class Priority
    {
        [PrimaryKey, AutoIncrement]
        public int Id { get; set; }
        public string PriorityName { get; set; }
        public string PriorityColor { get; set; }
    }
}

列表页CollectionView布局

<ScrollView VerticalScrollBarVisibility="Never">
    <StackLayout>
        <CollectionView ItemsSource="{Binding ItemsList}">
            <CollectionView.ItemsLayout>
                <LinearItemsLayout ItemSpacing="20" Orientation="Vertical" />
            </CollectionView.ItemsLayout>
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <StackLayout>
                        <Grid
                            Margin="0,0,0,20"
                            Padding="10"
                            xct:CornerRadiusEffect.CornerRadius="12"
                            BackgroundColor="{Binding ItemPriority.PriorityColor}"
                            RowDefinitions="*,20,20"
                            RowSpacing="10">
                            <Frame
                                Grid.Row="0"
                                Padding="5"
                                HorizontalOptions="Start">
                                <Label Text="{Binding ItemPriority.PriorityName}" />
                            </Frame>
                            <Label
                                Grid.Row="1"
                                Text="{Binding Name}"
                                TextColor="Black" />
                            <Label
                                Grid.Row="2"
                                Text="{Binding Description}"
                                TextColor="Black" />
                        </Grid>
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>
</ScrollView>

列表页ViewModel代码

#region constructor
public ListItemsViewmodel(INavigation navigation)
{
    Navigation = navigation;
    _itemsService = new ItemsService();
    LoadItems();
    GoAddItemPageCommand = new Command(ExecuteGoAddItemPageCommand);
    LoadItemsCommand = new Command(ExecuteLoadItemsCommand);
}
#endregion

#region commands 
public ICommand GoAddItemPageCommand { get; set; }
public ICommand LoadItemsCommand { get; set; }
#endregion

#region methods
private void LoadItems()
{
    var items = _itemsService.GetAllItems();
    ItemsList = new ObservableCollection<Item>(items);
}
#endregion

问题原因分析

  1. SQLite-net仅声明[ManyToOne]属性无法自动处理关联关系,需要配合外键字段存储子对象的ID
  2. 保存时未先存储子对象(Priority),导致Item无法关联到有效的Priority记录
  3. 读取数据时未主动加载关联的子对象,导致列表页无法获取Priority的具体数据

解决方案

1. 修改Item模型,添加外键字段

在Item类中新增外键字段,并配置ManyToOne关联的外键映射:

namespace CrudTarefas.Models
{
    [Table("Items")]
    public class Item
    {
        [PrimaryKey, AutoIncrement] 
        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }

        // 新增外键字段,存储Priority的ID
        public int PriorityId { get; set; }

        // 配置ManyToOne关联,指定关联的外键字段
        [ManyToOne(nameof(PriorityId))]
        public Priority ItemPriority { get; set; }
    }
}

2. 调整保存逻辑,先存Priority再存Item

需要先将Priority保存到数据库获取自增ID,再关联到Item的外键字段:

private async void ExecuteSaveItemsCommand()
{
    try
    {
        // 先创建并保存Priority
        var priority = new Priority()
        {
            PriorityName = PrioritySave,
            PriorityColor = "#ccc"
        };
        // 确保已实现PriorityService的Insert方法
        _priorityService.InsertPriority(priority);

        // 创建Item并关联Priority的ID
        Item itemSaved = new Item
        {
            Name = NameSave,
            Description = DescriptionSave,
            PriorityId = priority.Id,
            ItemPriority = priority
        };

        _itemsService.InsertItem(itemSaved);
        ExecuteBackProductPageCommand();
    }
    catch (Exception ex)
    {
        await Shell.Current.DisplayAlert("Error", ex.Message, "OK");
    }
}

3. 修改读取逻辑,加载关联数据

在获取Item列表时,使用WithChildren()方法自动加载关联的Priority对象:

// 在ItemsService的GetAllItems方法中修改
public List<Item> GetAllItems()
{
    using (var conn = new SQLiteConnection(_dbPath))
    {
        // 加载关联的Priority子对象
        return conn.Table<Item>().WithChildren().ToList();
    }
}

4. 更新数据库结构

修改模型后,删除旧的数据库文件(测试环境),让SQLite自动生成包含PriorityId字段的新表结构;生产环境需执行数据库迁移。


内容的提问来源于stack exchange,提问作者Sergio Gabriel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 14:33:20