从 .net maui 中的 sqlite 数据库检索数据时出错

问题描述 投票:0回答:1

您好,我正在尝试构建一个测验应用程序来构建一个测验应用程序,其中将从我项目中的数据文件夹中名为 cbt.db 的 sqlite 数据库中检索问题。但是,每当我运行该应用程序时,它都会返回以下错误:“System.ArgumentOutOfRangeException:'索引超出范围。必须为非负数且小于集合的大小。(参数'索引')'”在行中QuizViewModel 中有

currentQuestion = Questions[_currentQuestionIndex];
。我尝试将 _currentQuestionIndex 设置为 1,但仍然不起作用。我只想在处理测验逻辑之前用第一个问题填充标签。

数据库结构如下:

有一个问题表,其中有一个从1开始的question_id和question_text字段。还有一个答案表,其中也有 Question_id、answer_id、answer_text 和 is_ Correct 字段。 answer_id 适用于每个单独的答案,其中 Question_id 映射到问题表的答案。

这是我的模型类:Question.cs

using ColumnAttribute = SQLite.ColumnAttribute;

namespace CBT.Models;


public class Question
{
    [Column("question_id")]
    public int Id { get; set; }

    [Column("question_text")]
    public string? QuestionText { get; set; }

    [Column("category_id")]
    public int CategoryID { get; set; }

    public List<Answer>? Answers { get; set; }
}

public class Answer
{
    [Column("question_id")]
    public int Id { get; set; }

    [Column("answer_id")]
    public int AnswerID { get; set; }

    [Column("answer_text")]
    public string? AnswerText { get; set; }

    [Column("is_correct")]
    public bool IsCorrect { get; set; }
}

这是 DBService 接口:IDBService.cs

namespace CBT.Services;

public interface IDBService
{
    Task<List<Question>> GetQuestionsAsync();
    Task<Question> GetQuestionAsync(int id);
    Task<int> SaveQuestionAsync(Question question);
    Task<int> DeleteQuestionAsync(int id);

    Task<List<Answer>> GetAnswersAsync();
    Task<Answer> GetAnswerAsync(int id);
}

这是DBService.cs

using CBT.Models;

namespace CBT.Services;

class DBService : IDBService
{
    // The database connection object
    public static SQLiteAsyncConnection? database;

    // Get the database path from the app data directory
    public static string DBPath { get; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CBT_App.Data.cbt.db");

    // The constructor initializes the database connection and creates the table if not exists
    public DBService()
    {
        // Create the table for the question model class if not exists
        database.CreateTableAsync<Question>();

        // Create the table for the answer model class if not exists
        database.CreateTableAsync<Answer>();
    }

    // This method returns a list of all items in the database
    public async Task<List<Question>> GetQuestionsAsync()
    {
        return await database.Table<Question>().ToListAsync();
    }

    public async Task<List<Answer>> GetAnswersAsync()
    {
        return await database.Table<Answer>().ToListAsync();
    }

    // This method returns a specific item by its id
    public async Task<Question> GetQuestionAsync(int id)
    {
        return await database.Table<Question>().Where(i => i.Id == id).FirstOrDefaultAsync();
    }
    public async Task<Answer> GetAnswerAsync(int id)
    {
        return await database.Table<Answer>().Where(i => i.Id == id).FirstOrDefaultAsync();
    }

    // This method inserts a new item or updates an existing one
    public async Task<int> SaveQuestionAsync(Question question)
    {
        if (question.Id != 0)
        {
            // Update an existing item
            return await database.UpdateAsync(question);
        }
        else
        {
            // Insert a new item
            return await database.InsertAsync(question);
        }
    }

    // This method deletes an item by its id
    public async Task<int> DeleteQuestionAsync(int id)
    {
        return await database.DeleteAsync<Question>(id);
    }

}

这是App.xaml.cs

namespace CBT;

public partial class App : Application
{
    public App()
    {
        if(!File.Exists(DBService.DBPath))
        {
            var assembly = IntrospectionExtensions.GetTypeInfo(typeof(App)).Assembly;
            using Stream? stream = assembly.GetManifestResourceStream("CBT.Data.cbt.db");
            using MemoryStream? memoryStream = new();
            stream.CopyTo(memoryStream);
            File.WriteAllBytes(DBService.DBPath, memoryStream.ToArray());
        }

        DBService.database = new SQLiteAsyncConnection(DBService.DBPath, Constants.Flags);

        InitializeComponent();

        MainPage = new AppShell();
    }
}

这是 QuizViewModel.cs

namespace CBT.ViewModels;

public partial class QuizViewModel : ObservableObject
{
    readonly IDBService dbService;
    private int _currentQuestionIndex;
    private int _currentAnswerIndex;
    public ObservableCollection<Question> Questions { get; } = [];
    //public Question? currentQuestion => Questions[_currentQuestionIndex];
    public ObservableCollection<Answer> Answers { get; } = [];
    //public Answer currentAnswer => Answers[_currentAnswerIndex];

    [ObservableProperty]
    public Question currentQuestion;

    [ObservableProperty]
    public Answer currentAnswer;

    [ObservableProperty]
    public string? currentAnswerText;

    [ObservableProperty]
    public bool currentAnswerIsCorrect;
  
    public QuizViewModel(IDBService dBService)
    {
        this.dbService = dBService;
        Task getQuestionsAsync = GetQuestionsAsync();
        Task getAnswersAsync = GetAnswersAsync();

        currentQuestion = Questions[_currentQuestionIndex];
        currentAnswer = Answers[_currentAnswerIndex];

        currentAnswerText = CurrentQuestion.Answers[_currentAnswerIndex].AnswerText;
        currentAnswerIsCorrect = CurrentQuestion.Answers[_currentAnswerIndex].IsCorrect;

        NextQuestion();
        NextAnswers();

    }

    

    [RelayCommand]
    async Task GetQuestionsAsync()
    {
        try
        {
            var questions = await dbService.GetQuestionsAsync();
            if(questions.Count != 0)
            {
                Questions.Clear();
            }
            foreach(var question in questions)
            {
                Questions.Add(question);
            }
        } 
        catch(Exception ex)
        {
            Debug.Print($"Unable to get questions: {ex.Message}");
        }
    }


    [RelayCommand]
    async Task GetAnswersAsync()
    {
        try
        {
            var answers = await dbService.GetAnswersAsync();
            if (answers.Count != 0)
            {
                Answers.Clear();
            }
            foreach (var answer in answers)
            {
                Answers.Add(answer);
            }
        }
        catch (Exception ex)
        {
            Debug.Print($"Unable to get answers: {ex.Message}");
        }
    }

    [RelayCommand]
    private void NextQuestion()
    {
        if (_currentQuestionIndex < Questions.Count - 1)
        {
            _currentQuestionIndex++;
            _currentAnswerIndex = 0;
        }
    }

    [RelayCommand]
    private void NextAnswers()
    {
        if (_currentAnswerIndex < CurrentQuestion.Answers.Count - 1)
        {
            _currentAnswerIndex ++;
        }
    }

    
}

测验页面.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CBT.Views.QuizPage"
             Title="QuizPage"
             xmlns:vm="clr-namespace:CBT.ViewModels"
             xmlns:model="clr-namespace:CBT.Models"
             x:DataType="vm:QuizViewModel">
    <VerticalStackLayout>
        <Label x:Name="questionLabel"
            VerticalOptions="Center" 
            HorizontalOptions="Center" />

            <Label x:Name="answer1Label"
            VerticalOptions="Center" 
            HorizontalOptions="Center" />

            <Label x:Name="answer2Label"
            VerticalOptions="Center" 
            HorizontalOptions="Center" />

            <Label x:Name="answer3Label"
            VerticalOptions="Center" 
            HorizontalOptions="Center" />

            <Label x:Name="answer4Label"
            VerticalOptions="Center" 
            HorizontalOptions="Center" />
    </VerticalStackLayout>

</ContentPage>

测验页面.xaml.cs

namespace CBT.Views;

public partial class QuizPage : ContentPage
{
    public QuizPage(QuizViewModel quizViewModel)
    {
        InitializeComponent();

        Populate(quizViewModel);
    }

    public void Populate(QuizViewModel quizViewModel)
    {
        questionLabel.Text = quizViewModel.CurrentQuestion.QuestionText;
    }
}

AppShell.xaml

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="CBT.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:views="clr-namespace:CBT.Views"
    xmlns:local="clr-namespace:CBT">

    <ShellContent
        Shell.NavBarIsVisible="true"
        Title="Main"
        Icon="iconblank.png"
        ContentTemplate="{DataTemplate views:QuizPage}"
        Route="QuizPage" />
</Shell>

常量.cs

namespace CBT
{
    public static class Constants
    {
        public const SQLiteOpenFlags Flags =
            // open the database in read/write mode
            SQLiteOpenFlags.ReadWrite |
            // create the database if it doesn't exist
            SQLiteOpenFlags.Create |
            // enable multi-threaded database access
            SQLiteOpenFlags.SharedCache;
    }
}

MauiProgram.cs

namespace CBT;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder.UseMauiApp<App>().UseMauiCommunityToolkitCore();
        builder
            .UseMauiApp<App>()
            .UseMauiCommunityToolkit()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
            });

        builder.Services.AddSingleton<IDBService, DBService>();
        builder.Services.AddSingleton<INavigationService, NavigationService>();

        builder.Services.AddSingleton<MainViewModel>();
        builder.Services.AddSingleton<MainPage>();

        builder.Services.AddTransient<QuizViewModel>();
        builder.Services.AddTransient<QuizPage>();

        return builder.Build();
    }
}

GlobalUsings.cs

global using CommunityToolkit.Mvvm.ComponentModel;
global using CommunityToolkit.Mvvm.Input;
global using CBT.ViewModels;
global using CBT.Views;
global using CBT.Models;
global using CBT.Services;
global using System.Collections.ObjectModel;
global using System.ComponentModel;
global using System.Diagnostics;
global using System.Globalization;
global using System.Runtime.CompilerServices;
global using System.Text.Json;
global using System.Threading.Tasks;
global using System;
global using System.Reflection;
global using System.Collections.Generic;
global using System.Linq;
global using System.Text;
global using SQLite;
global using CommunityToolkit.Maui;
global using CommunityToolkit.Maui.Core;
c# sqlite maui
1个回答
0
投票

System.ArgumentOutOfRangeException:'索引超出范围。必须是 非负且小于集合的大小。 (范围 'index')'" 行中有 currentQuestion = 问题[_currentQuestionIndex];在 QuizViewModel 中

错误原因是列表中没有index(

_currentQuestionIndex
)值的项目。

并且从您分享的代码中,我们可以发现您想要使用代码

Questions
访问
currentQuestion = Questions[_currentQuestionIndex];
中的元素,但是此时
Questions
并没有代码
 Task getQuestionsAsync = GetQuestionsAsync();
之后的元素。这行代码
 currentAnswer = Answers[_currentAnswerIndex];
也很有可能有这个问题

public QuizViewModel(IDBService dBService)
{
    this.dbService = dBService;
    Task getQuestionsAsync = GetQuestionsAsync();
    Task getAnswersAsync = GetAnswersAsync();

    currentQuestion = Questions[_currentQuestionIndex];
    currentAnswer = Answers[_currentAnswerIndex];

    currentAnswerText = CurrentQuestion.Answers[_currentAnswerIndex].AnswerText;
    currentAnswerIsCorrect = CurrentQuestion.Answers[_currentAnswerIndex].IsCorrect;
}
© www.soinside.com 2019 - 2024. All rights reserved.