Сохраненные элементы пусты при извлечении в более поздний момент

Я использую Xamarin и C# для создания кроссплатформенного приложения. Расширения SQLite.Net используются для локальной базы данных. Таблица User содержит список регистров, как показано ниже:

public class User
{
    [PrimaryKey, AutoIncrement]
    public int UserID { get; set; }
    public string firstName { get; set; }
    public string lastName { get; set; }
    public string title { get; set; }
    public string emailAddress { get; set; }
    public string password { get; set; }      
    //public ObservableCollection<Register> registerList { get; set; }

    [ManyToMany(typeof(RegStudent))]
    public ObservableCollection<Register> Registers { get; set; } 

    public User()
    {
        this.Registers = new ObservableCollection<Register>();
    }

    public void addRegisterAccess(Register register)
    {
        Registers.Add(register);
    }
}

Когда создан регистр, он добавляется в таблицу регистров, а затем добавляется в этот список, как показано ниже:

//Set the register to the updated version of this register that is stored on db, 
//as current register that has been created through user input does not have an ID.
register = database.db.GetRegisterByNameAndLocation(register.Name, register.Location);

//Add the register to the current user list of registers. Then fetch the new info and set the current user
// from the db.
database.db.GetUserByEmail(currentUser.user.emailAddress).addRegisterAccess(register);

Когда я пытаюсь получить доступ к списку регистров через пользовательский объект, он говорит, что список не содержит никаких элементов.

Я искал решения, и они, кажется, упоминают SQLite UpdateWithChildren, но этот метод не существует в моем соединении SQLite или в моей базе данных. Список регистров - это отношение ManyToMany, как обновление вписывается во все это?

** РЕДАКТИРОВАТЬ: ** Теперь у меня есть метод обновления, но, похоже, возникает исключение, когда он попадает. Ниже приведен метод в моем «DatabaseManager», который добавляет регистр в список пользователей:

public void addRegisterAccess(User user, Register register)
    {
        user.Registers.Add(register);
        _connection.InsertOrReplaceWithChildren(user, true);
    }

Исключение ниже дается при добавлении регистра, я думал, что код для связывания классов (с использованием промежуточной таблицы) не нужно вызывать кодом пользователя?

    02-10 12:09:51.662 E/AndroidRuntime( 4461): Caused by: md52ce486a14f4bcd95899665e9d932190b.JavaProxyThrowable: SQLiteNetExtensions.Exceptions.IncorrectRelationshipException: User.Registers: ManyToMany relationship origin must have a foreign key defined in the intermediate type
02-10 12:09:51.662 E/AndroidRuntime( 4461):   at SQLiteNetExtensions.Extensions.WriteOperations.Assert (Boolean assertion, System.Type type, System.Reflection.PropertyInfo property, System.String message) <0xd84bb6e8 + 0x00087> in <filename unknown>:0 
02-10 12:09:51.662 E/AndroidRuntime( 4461):   at SQLiteNetExtensions.Extensions.WriteOperations.UpdateManyToManyForeignKeys (SQLite.Net.SQLiteConnection conn, System.Object element, System.Reflection.PropertyInfo relationshipProperty) <0xd84b9750 + 0x0026b> in <filename unknown>:0 
02-10 12:09:51.662 E/AndroidRuntime( 4461):   at SQLiteNetExtensions.Extensions.WriteOperations.UpdateInverseForeignKeys (SQLite.Net.SQLiteConnection conn, System.Object element) <0xd84b9578 + 0x0014f> in <filename unknown>:0 
02-10 12:09:51.662 E/AndroidRuntime( 4461):   at SQLiteNetExtensions.Extensions.WriteOperations.UpdateWithChildren (SQLite.Net.SQLiteConnection conn, System.Object element) <0xd84b8a68 + 0x0003b> in <filename unknown>:0 
02-10 12:09:51.662 E/AndroidRuntime( 4461):   at SQLiteNetExtensions.Extensions.WriteOperations.InsertWithChildrenRecursive (SQLite.Net.SQLiteConnection conn, System.Object element, Boolean replace, Boolean recursive, ISet`1 objectCache) <0xd84b76f8 + 0x000af> in <filename unknown>:0 
02-10 12:09:51.662 E/AndroidRuntime( 4461):   at SQLiteNetExtensions.Extensions.WriteOperations.InsertOrReplaceWithChildren (SQLite.Net.SQLiteConnection conn, System.Object element, Boolean recursive) <0xd84b76a8 + 0x0002f> in <filename unknown>:0 
02-10 12:09:51.662 E/AndroidRuntime( 4461):   at RegistrationApp.Data.DatabaseManager.addRegisterAccess (RegistrationApp.User user, RegistrationApp.Models.Register register) <0xd84b7578 + 0x0003f> in <filename unknown>:0 
02-10 12:09:51.662 E/AndroidRuntime( 4461):   at RegistrationApp.CreateRegisterPage+<OnCreateButtonClicked>d__1b.MoveNext () <0xd87ad788 + 0x006c3> in <filename unknown>:0 
02-10 12:09:51.662 E/AndroidRuntime( 4461): --- End of stack trace from previous location where exception was thrown ---

Просто добавлю, что мой класс промежуточной таблицы выглядит так:

public class RegUser
    {
        [ForeignKey(typeof(User))]
        public int UserID { get; set; }

        [ForeignKey(typeof(Register))]
        public int RegisterID { get; set; }
    }

** РЕДАКТИРОВАТЬ: ** Ниже приведен сам класс регистрации:

public class Register
    {
        [PrimaryKey, AutoIncrement]
        public int RegisterID { get; set; }
        public string Name { get; set; }
        public string Type { get; set; }
        public string Location { get; set; }
        public DateTime Date { get; set; }
        public string StartTime { get; set; }
        public string EndTime { get; set; }
        public Boolean Recurring { get; set; }

        [ManyToMany(typeof(RegStudent), "StudentID", "Registers")]
        public ObservableCollection<KeyValuePair<Student, string>> StudentList { get; set; }

        [ManyToMany(typeof(RegUser), "UserID", "Registers")]
        public ObservableCollection<User> UserList { get; set; }

        public Register()
        {
            this.StudentList = new ObservableCollection<KeyValuePair<Student, string>>();
            this.UserList = new ObservableCollection<User>();
        }

        //Adds a student to the Student List for this register, marking the string value as '-', to show the register has not been taken yet.
        //This value will be set to the status of the student, to show them as Present, AWOL, Sick, Late, etc.
        public void addStudent(Student student)
        {
            StudentList.Add(new KeyValuePair<Student, string>(student, "-"));
        }
    } 

person user2283597    schedule 10.02.2016    source источник
comment
Попробуйте добавить using SQLiteNetExtensions.Extensions;, чтобы сделать доступным метод UpdateWithChildren.   -  person redent84    schedule 10.02.2016
comment
@ redent84 Не могу поверить, что пропустил это. Я использовал этот метод, но он выдает исключение, которого я раньше не видел. Я обновил вопрос, чтобы показать код и исключение.   -  person user2283597    schedule 10.02.2016
comment
@ redent84 Я пытался использовать InsertOrUpdateWithChildren, но вместо этого пытался использовать UpdateWithChildren. Теперь я получаю другое исключение, в котором говорится: `SQLiteNetExtensions.Exceptions.IncorrectRelationshipException: Register.StudentList: место назначения отношения ManyToMany должно иметь первичный ключ`... единственное решение, которое я смог найти в Интернете, не помогло решить эту проблему. Любая идея, где я должен искать, чтобы предотвратить эксцессию? Спасибо за помощь   -  person user2283597    schedule 11.02.2016
comment
В вашем Register классе есть PrimaryKey?   -  person redent84    schedule 11.02.2016
comment
@ redent84 Да, это [PrimaryKey, AutoIncrement] public int RegisterID { get; set; }.   -  person user2283597    schedule 11.02.2016
comment
Попробуйте добавить PrimaryKey к RegUser   -  person redent84    schedule 11.02.2016
comment
@ redent84 Я добавил PrimaryKey (автоматически увеличивающийся до RegUser и RegStudent, но я все еще получаю исключение, говорящее Register.StudentList: ManyToMany relationship destination must have Primary Key, при попытке добавить регистр в список пользователей.   -  person user2283597    schedule 11.02.2016
comment
Можете ли вы опубликовать свой код Register? проблема скорее всего там   -  person redent84    schedule 11.02.2016
comment
@redent84 добавил к вопросу код Register   -  person user2283597    schedule 11.02.2016


Ответы (1)


Вы создаете список KeyValuePair и, таким образом, получаете ошибку, что KeyValuePair не имеет первичного ключа:

[ManyToMany(typeof(RegStudent), "StudentID", "Registers")]
public ObservableCollection<KeyValuePair<Student, string>> StudentList { get; set; }

Измените его на список Student:

[ManyToMany(typeof(RegStudent), "StudentID", "Registers")]
public ObservableCollection<Student> StudentList { get; set; }

Если вам нужно хранить информацию в отношении, вы должны хранить ее в классе RegUser:

public class RegUser
{
    [ForeignKey(typeof(User))]
    public int UserID { get; set; }

    [ForeignKey(typeof(Register))]
    public int RegisterID { get; set; }

    public string Status { get; set; }
}

Имейте в виду, что расширения SQLite-Net в настоящее время не поддерживают дополнительные свойства в промежуточных таблицах, и вам придется получать эту информацию вручную:

var regUser = conn.Table<RegUser>.Where(ru => ru.UserID == user.ID && ru.RegisterID == register.ID).FirstOrDefault();
if (regUser != null) {
    var status = regUser.Status;
}
person redent84    schedule 12.02.2016
comment
Спасибо за ответ, он полностью устраняет проблему исключения. Однако первоначальная проблема пустых списков, даже если элементы были добавлены, все еще существует. Я пробовал использовать UpdateWithChildren(register), а также пробовал InsertOrReplaceWithChildren(register) во время создания учащегося или регистрации, но списки по-прежнему ничего не показывают. - person user2283597; 14.02.2016
comment
Я еще раз посмотрел, как я добавляю элементы в базу данных, кажется, что элементы добавляются правильно, но списки всегда пусты. Есть ли особый способ добавления элементов в список объектов SQLiteNetExtensions? - person user2283597; 17.02.2016
comment
Если они правильно добавлены в базу данных, возможно, вы их не извлекаете. Чтобы получить отношения, вы должны использовать любой из методов выборки WithChildren или использовать метод GetChildren позже для объекта. - person redent84; 17.02.2016
comment
Ах, я использовал метод Table из примера, основанного на SQLite.Net, а не на расширениях. В настоящее время список заполняется без каких-либо исключений. Танки - person user2283597; 18.02.2016