Проблема с расширениями SQLite.Net с InsertOrReplaceWithChildren

Я использую SQLite-Net PCL вместе с расширениями SQLite-Net для разработки приложения с использованием Xamarin.

У меня есть два класса A и B, определенные следующим образом:

public class A
{

    [PrimaryKey, AutoIncrement]
    public int Id
    {
        get;
        set;
    }

    [Unique]
    public string Name
    {
        get;
        set;
    }

    [OneToMany(CascadeOperations = CascadeOperation.All)]
    public List<B> Sons
    {
        get;
        set;
    }

    public A(string name, List<B> sons)
    {
        Name = name;
        Sons = sons;
    }

}

public class B
{

    [PrimaryKey, AutoIncrement]
    public int Id
    {
        get;
        set;
    }

    [Unique]
    public string Name
    {
        get;
        set;
    }

    public string LastModified
    {
        get;
        set;
    }

    [ForeignKey(typeof(A))]
    public int FatherId
    {
        get;
        set;
    }

    [ManyToOne]
    public A Father
    {
        get;
        set;
    }

    public B()
    {
    }

    public B(string name)
    {
        Name = name;
    }

}

Я пытаюсь использовать вставку или замену следующим образом:

        var sons1 = new List<B>
        {
            new B("uno"),
        };

        var a1 = new A("padre", sons1);

        var sons2 = new List<B>
        {
            new B("uno2"),
        };

        var a2 = new A("padre", sons2);

        using (var conn = DatabaseStore.GetConnection())
        {
            conn.DeleteAll<A>();
            conn.DeleteAll<B>();
        }

        using (var conn = DatabaseStore.GetConnection())
        {
            conn.InsertOrReplaceWithChildren(a1, true);
            conn.InsertOrReplaceWithChildren(a2, true);
        }

Проблема в том, что второй InsertOrReplaceWithChildren выдает исключение Constraint, которое не выбрасывается, если мы удаляем уникальное ограничение для A.Name. Разве InsertOrReplaceWithChildren не заменяет объект, если уникальное ограничение нарушается?


person papafe    schedule 18.03.2015    source источник
comment
Похоже на ошибку. Вероятно здесь: bitbucket.org/twincoders/sqlite-net-extensions/src/   -  person redent84    schedule 18.03.2015


Ответы (1)


Я проверил коммиты для этой строки, теперь я помню: кажется, что первичный ключ AutoIncrement работает только для операторов Insert, а не для InsertOrReplace. Как следствие, если вы вызываете InsertOrReplace с первичным ключом AutoIncrement, установленным на 0, он всегда будет перезаписывать одно и то же значение в базе данных с идентификатором 0 вместо правильного добавления новых значений.

Эту проблему легко проверить, выполнив этот тест:

var a = new List<A> {
    new A("a1", null),
    new A("a2", null),
    new A("a3", null),
    new A("a4", null),
    new A("a5", null),
    new A("a6", null)
};

foreach (var element in a) {
    conn.InsertOrReplace(element);
}

// Will fail expecting 6 elements but returning only 1
Assert.AreEqual(a.Count, conn.Table<A>().ToList().Count);

Чтобы решить эту проблему, вы должны отказаться либо от первичного ключа AutoIncrement, либо от проверки ограничения Unique, чтобы инструкция InsertOrReplace работала.

Это замещающие классы, которые должны работать должным образом, отказавшись от AutoIncrement первичных ключей:

public class A
{

    [PrimaryKey]
    public Guid Id { get; set; }

    [Unique]
    public string Name { get; set; }

    [OneToMany(CascadeOperations = CascadeOperation.All)]
    public List<B> Sons { get; set; }

    public A() {}
    public A(string name, List<B> sons)
    {
        Id = Guid.NewGuid();
        Name = name;
        Sons = sons;
    }
}

public class B
{

    [PrimaryKey]
    public Guid Id { get; set; }

    [Unique]
    public string Name { get; set; }

    public string LastModified { get; set; }

    [ForeignKey(typeof(A))]
    public Guid FatherId { get; set; }

    [ManyToOne]
    public A Father { get; set; }

    public B() {}

    public B(string name)
    {
        Id = Guid.NewGuid();
        Name = name;
    }
}

Надеюсь, поможет.

person redent84    schedule 18.03.2015
comment
Спасибо за вашу помощь. На самом деле я работаю над моделью данных, которая сложнее этой, поэтому каждый раз, когда я вставляю, я проверяю, существует ли уже объект. Честно говоря, у меня была еще одна более странная проблема, которую, к сожалению, мне не удалось воспроизвести на меньшем примере, но я нашел обходной путь и для нее. - person papafe; 18.03.2015
comment
Кроме того, я думаю, что источник путаницы также дает тот факт, что ваш пример будет работать с InsertOrReplaceWithChildren и он будет правильно назначать идентификаторы - person papafe; 18.03.2015