Как работать с вложенными классами и списками в моей таблице?

Я использую SQLite в качестве базы данных, и у меня есть следующая таблица, которая работает, когда я ее создаю:

public class TodoItem
{
    [PrimaryKey, AutoIncrement]
    public int ID { get; set; }
    public string Name { get; set; }
    public string Notes { get; set; }
    public bool Done { get; set; }
    public Gender Gender { get; set; }
    public DateTime? DateOfBirth { get; set; }
}

При создании таблицы

database.CreateTableAsync<TodoItem>().Wait();

теперь я получаю некоторые ошибки, если хочу включить вложенный объект:

public class Test
{
    [PrimaryKey, AutoIncrement]
    public int AnotherID { get; set; }
    public string Name { get; set; }
}
public class TodoItem
{
    [PrimaryKey, AutoIncrement]
    public int ID { get; set; }
    public string Name { get; set; }
    public string Notes { get; set; }
    public bool Done { get; set; }
    public Gender Gender { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public Test Test { get; set; }
}

Я получаю следующую ошибку

UNHANDLED EXCEPTION:
 System.AggregateException: One or more errors occurred. ---> System.NotSupportedException: Don't know about Todo.Test
   at SQLite.Orm.SqlType (SQLite.TableMapping+Column p, System.Boolean storeDateTimeAsTicks) [0x001ad] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:2080 
   at SQLite.Orm.SqlDecl (SQLite.TableMapping+Column p, System.Boolean storeDateTimeAsTicks) [0x00000] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:2027 
   at SQLite.SQLiteConnection.<CreateTable>m__0 (SQLite.TableMapping+Column p) [0x00000] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:417 
   at System.Linq.Enumerable+SelectArrayIterator`2[TSource,TResult].ToArray () [0x00012] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/external/corefx/src/System.Linq/src/System/Linq/Select.cs:251 
   at System.Linq.Enumerable.ToArray[TSource] (System.Collections.Generic.IEnumerable`1[T] source) [0x00015] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/external/corefx/src/System.Linq/src/System/Linq/ToCollection.cs:19 
   at SQLite.SQLiteConnection.CreateTable (System.Type ty, SQLite.CreateFlags createFlags) [0x00133] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:418 
   at SQLite.SQLiteAsyncConnection+<CreateTablesAsync>c__AnonStorey0.<>m__0 () [0x0002f] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLiteAsync.cs:108 
   at System.Threading.Tasks.Task`1[TResult].InnerInvoke () [0x0000f] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Future.cs:680 
   at System.Threading.Tasks.Task.Execute () [0x00010] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:2502 
    --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional (System.Boolean includeTaskCanceledExceptions) [0x00011] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:2157 
   at System.Threading.Tasks.Task.Wait (System.Int32 millisecondsTimeout, System.Threading.CancellationToken cancellationToken) [0x00043] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:3189 
   at System.Threading.Tasks.Task.Wait () [0x00000] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:3054 
   at Todo.TodoItemDatabase..ctor (System.String dbPath) [0x00015] in C:\Users\some-user\Documents\Visual Studio 2015\Projects\Todo\Todo\Data\TodoItemDatabase.cs:14 
   at Todo.App.get_Database () [0x0000e] in C:\Users\some-user\Documents\Visual Studio 2015\Projects\Todo\Todo\App.cs:32 
   at Todo.TodoListPage+<OnAppearing>d__1.MoveNext () [0x0002c] in C:\Users\some-user\Documents\Visual Studio 2015\Projects\Todo\Todo\Views\TodoListPage.xaml.cs:20 
 --- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:151 
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b_
public class TodoItem
{
    [PrimaryKey, AutoIncrement]
    public int ID { get; set; }
    public string Name { get; set; }
    public string Notes { get; set; }
    public bool Done { get; set; }
    public Gender Gender { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public List<string> Strings { get; set; }
}
0 (System.Object state) [0x00000] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1018 at Android.App.SyncContext+<>c__DisplayClass2_0.<Post>b__0 () [0x00000] in /Users/builder/data/lanes/4695/448f54fd/source/xamarin-android/src/Mono.Android/Android.App/SyncContext.cs:35 at Java.Lang.Thread+RunnableImplementor.Run () [0x00008] in /Users/builder/data/lanes/4695/448f54fd/source/xamarin-android/src/Mono.Android/Java.Lang/Thread.cs:36 at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in /Users/builder/data/lanes/4695/448f54fd/source/xamarin-android/src/Mono.Android/obj/Release/android-23/mcw/Java.Lang.IRunnable.cs:81 at (wrapper dynamic-method) System.Object:4ad81135-c1dd-4bba-bca3-4e991f58da69 (intptr,intptr) ---> (Inner Exception #0) System.NotSupportedException: Don't know about Todo.Test at SQLite.Orm.SqlType (SQLite.TableMapping+Column p, System.Boolean storeDateTimeAsTicks) [0x001ad] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:2080 at SQLite.Orm.SqlDecl (SQLite.TableMapping+Column p, System.Boolean storeDateTimeAsTicks) [0x00000] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:2027 at SQLite.SQLiteConnection.<CreateTable>m__0 (SQLite.TableMapping+Column p) [0x00000] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:417 at System.Linq.Enumerable+SelectArrayIterator`2[TSource,TResult].ToArray () [0x00012] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/external/corefx/src/System.Linq/src/System/Linq/Select.cs:251 at System.Linq.Enumerable.ToArray[TSource] (System.Collections.Generic.IEnumerable`1[T] source) [0x00015] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/external/corefx/src/System.Linq/src/System/Linq/ToCollection.cs:19 at SQLite.SQLiteConnection.CreateTable (System.Type ty, SQLite.CreateFlags createFlags) [0x00133] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:418 at SQLite.SQLiteAsyncConnection+<CreateTablesAsync>c__AnonStorey0.<>m__0 () [0x0002f] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLiteAsync.cs:108 at System.Threading.Tasks.Task`1[TResult].InnerInvoke () [0x0000f] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Future.cs:680 at System.Threading.Tasks.Task.Execute () [0x00010] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:2502 <---

Если я использую List

public class TodoItem
{
    [PrimaryKey, AutoIncrement]
    public int ID { get; set; }
    public string Name { get; set; }
    public string Notes { get; set; }
    public bool Done { get; set; }
    public Gender Gender { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public List<string> Strings { get; set; }
}

я получил

 UNHANDLED EXCEPTION:
 System.AggregateException: One or more errors occurred. ---> System.NotSupportedException: Don't know about System.Collections.Generic.List`1[System.String]
   at SQLite.Orm.SqlType (SQLite.TableMapping+Column p, System.Boolean storeDateTimeAsTicks) [0x001ad] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:2080 
   at SQLite.Orm.SqlDecl (SQLite.TableMapping+Column p, System.Boolean storeDateTimeAsTicks) [0x00000] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:2027 
   at SQLite.SQLiteConnection.<CreateTable>m__0 (SQLite.TableMapping+Column p) [0x00000] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:417 
   at System.Linq.Enumerable+SelectArrayIterator`2[TSource,TResult].ToArray () [0x00012] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/external/corefx/src/System.Linq/src/System/Linq/Select.cs:251 
   at System.Linq.Enumerable.ToArray[TSource] (System.Collections.Generic.IEnumerable`1[T] source) [0x00015] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/external/corefx/src/System.Linq/src/System/Linq/ToCollection.cs:19 
   at SQLite.SQLiteConnection.CreateTable (System.Type ty, SQLite.CreateFlags createFlags) [0x00133] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:418 
   at SQLite.SQLiteAsyncConnection+<CreateTablesAsync>c__AnonStorey0.<>m__0 () [0x0002f] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLiteAsync.cs:108 
   at System.Threading.Tasks.Task`1[TResult].InnerInvoke () [0x0000f] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Future.cs:680 
   at System.Threading.Tasks.Task.Execute () [0x00010] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:2502 
    --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional (System.Boolean includeTaskCanceledExceptions) [0x00011] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:2157 
   at System.Threading.Tasks.Task.Wait (System.Int32 millisecondsTimeout, System.Threading.CancellationToken cancellationToken) [0x00043] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:3189 
   at System.Threading.Tasks.Task.Wait () [0x00000] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:3054 
   at Todo.TodoItemDatabase..ctor (System.String dbPath) [0x00015] in C:\Users\some-user\Documents\Visual Studio 2015\Projects\Todo\Todo\Data\TodoItemDatabase.cs:14 
   at Todo.App.get_Database () [0x0000e] in C:\Users\some-user\Documents\Visual Studio 2015\Projects\Todo\Todo\App.cs:32 
   at Todo.TodoListPage+<OnAppearing>d__1.MoveNext () [0x0002c] in C:\Users\some-user\Documents\Visual Studio 2015\Projects\Todo\Todo\Views\TodoListPage.xaml.cs:20 
 --- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:151 
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__6_0 (System.Object state) [0x00000] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1018 
   at Android.App.SyncContext+<>c__DisplayClass2_0.<Post>b__0 () [0x00000] in /Users/builder/data/lanes/4695/448f54fd/source/xamarin-android/src/Mono.Android/Android.App/SyncContext.cs:35 
   at Java.Lang.Thread+RunnableImplementor.Run () [0x00008] in /Users/builder/data/lanes/4695/448f54fd/source/xamarin-android/src/Mono.Android/Java.Lang/Thread.cs:36 
   at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in /Users/builder/data/lanes/4695/448f54fd/source/xamarin-android/src/Mono.Android/obj/Release/android-23/mcw/Java.Lang.IRunnable.cs:81 
   at (wrapper dynamic-method) System.Object:3ff99a1f-7842-4c41-b229-386570e8d19f (intptr,intptr)
 ---> (Inner Exception #0) System.NotSupportedException: Don't know about System.Collections.Generic.List`1[System.String]
   at SQLite.Orm.SqlType (SQLite.TableMapping+Column p, System.Boolean storeDateTimeAsTicks) [0x001ad] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:2080 
   at SQLite.Orm.SqlDecl (SQLite.TableMapping+Column p, System.Boolean storeDateTimeAsTicks) [0x00000] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:2027 
   at SQLite.SQLiteConnection.<CreateTable>m__0 (SQLite.TableMapping+Column p) [0x00000] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:417 
   at System.Linq.Enumerable+SelectArrayIterator`2[TSource,TResult].ToArray () [0x00012] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/external/corefx/src/System.Linq/src/System/Linq/Select.cs:251 
   at System.Linq.Enumerable.ToArray[TSource] (System.Collections.Generic.IEnumerable`1[T] source) [0x00015] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/external/corefx/src/System.Linq/src/System/Linq/ToCollection.cs:19 
   at SQLite.SQLiteConnection.CreateTable (System.Type ty, SQLite.CreateFlags createFlags) [0x00133] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLite.cs:418 
   at SQLite.SQLiteAsyncConnection+<CreateTablesAsync>c__AnonStorey0.<>m__0 () [0x0002f] in /Users/fak/Dropbox/Projects/sqlite-net/src/SQLiteAsync.cs:108 
   at System.Threading.Tasks.Task`1[TResult].InnerInvoke () [0x0000f] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Future.cs:680 
   at System.Threading.Tasks.Task.Execute () [0x00010] in /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs:2502 <---

Я использую Официальную портативную библиотеку SQLite-net 1.3.3. Должен ли я использовать такие атрибуты, как PrimaryKey, ForeignKey и т. д.? Как? Или библиотека может обрабатывать только примитивные типы данных?

Образец можно загрузить с здесь.

В этой проблеме говорится, что должна быть возможна работа с List, но не в последней версии. Я безуспешно пытался перейти на 1.2.0 и 1.3.1.

Изменить

Я установил SQLiteNetExtensions и изменил пример кода на

using SQLite;
using SQLiteNetExtensions.Attributes;
using System.Collections.Generic;

namespace Todo
{
    public class Test
    {
        [PrimaryKey, AutoIncrement]
        public int AnotherID { get; set; }
        public string Name { get; set; }
    }

    public class TodoItem
    {
        [PrimaryKey, AutoIncrement]
        public int ID { get; set; }
        public string Name { get; set; }
        public string Notes { get; set; }
        public bool Done { get; set; }
        [TextBlob("StringsBlobbed")]
        public List<string> Strings { get; set; }
        public string StringsBlobbed { get; set; }
    }
}

и я все еще получаю ту же ошибку.

Изменить 2

Я думаю, что есть путаница между библиотеками. SQLite-Net Extensions зависит от SQLite.Net-PCL v. 3.1.1 (Nuget). Но Xamarin связан с библиотекой sqlite-net-pcl v. 1.3.3 (Nuget).

SQLite.Net-PCL (oysteinkrog) является ответвлением sqlite-net-pcl (praeclarum). Кажется, что последний не совместим с SQLite-Net Extensions, что мне здесь и нужно. Но поддерживает ли SQLite.Net-PCL UWP? Он не обновлялся с 4 июня 2016 года. И самое смешное, что SQLite-Net Extensions ссылается на praeclarum, что неверно. Я проверил это, удалив все пакеты SQL Nuget и установив только SQLite-Net Extensions, что должно автоматически запускать необходимые зависимости. Что я могу сделать?


person testing    schedule 21.06.2017    source источник
comment
Не обсуждайте голоса в своем вопросе. В любом случае, я думаю, вам следует прочитать Как спросить и включить реальную ошибку. Произошла одна или несколько ошибок — AggregateException, которое содержит фактические исключения, возникшие в его свойстве InnerExceptions. Эти исключения содержат сообщения, которые вы можете дополнительно изучить, и не забудьте показать свое исследование в своем вопросе.   -  person CodeCaster    schedule 21.06.2017
comment
comment
Я пытался использовать SQLiteNetExtensions, но получаю ту же ошибку для списка (см. отредактированный вопрос). Разве нельзя работать с ForeignKey, чтобы вложить объект в объект?   -  person testing    schedule 21.06.2017


Ответы (1)


Чтобы иметь возможность работать с вложенными List или object, мне нужно SQLiteNetExtensions. Поскольку я использую другой пакет SQLite, отличный от зависимость по умолчанию от SQLiteNetExtensions у вас есть два варианта:

  1. Вручную добавьте проект в свое решение
    1.1. Загрузите исходный код для SQLiteNetExtensions
    1.2. Добавьте как проект SQLiteNetExtensions-PCL в свое решение
    1.3. Добавьте этот проект в качестве ссылки ко всем вашим проектам (портативным, iOS, Droid, UWP)

  2. Установите SQLiteNetExtensions 2.0.0- альфа2

Имейте в виду, если вы уже установили некоторые пакеты sql NuGet. Сначала удалите их все, а затем установите только SQLiteNetExtensions. Это добавит вам все необходимые зависимости.

Для List<string> вы можете сделать:

public class TodoItem
{
    [PrimaryKey, AutoIncrement]
    public int ID { get; set; }
    public string Name { get; set; }
    public string Notes { get; set; }
    public bool Done { get; set; }

    [TextBlob("StringsBlobbed")]
    public List<string> Strings { get; set; }
    public string StringsBlobbed { get; set; }
}

Если у вас есть другие типы списков, вам нужна связь [OneToMany].

Для работы с объектами вы должны уметь делать это< /а>:

public class Test
{
    [PrimaryKey, AutoIncrement]
    public string AnotherID { get; set; }
    public string Name { get; set; }
}

public class TodoItem
{
    [PrimaryKey, AutoIncrement]
    public int ID { get; set; }
    public string Name { get; set; }
    public string Notes { get; set; }
    public bool Done { get; set; }

    [ForeignKey(typeof(Test))]
    public string TestId { get; set; }

    [OneToOne]
    public Test Test { get; set; }
}

Хорошим руководством по работе с отношениями [OneToOne] (например, для объектов) является это здесь. [OneToMany] смотрите здесь.

Есть еще несколько шагов, таких как создание таблицы, получение и сохранение данных особым образом (GetWithChildren, UpdateWithChildren, ...). Также помните о CascadeOperations, который вы нужно, если у вас многоуровневая иерархия.

Если ошибка по-прежнему возникает, внимательно прочитайте журнал отладки. Нужно убедиться, что [ForeignKey] и [OneToOne] используются во всех классах, использующих объект.

person testing    schedule 21.06.2017