【问题标题】:SQLite.Net Extensions issue with InsertOrReplaceWithChildrenInsertOrReplaceWithChildren 的 SQLite.Net 扩展问题
【发布时间】:2015-03-18 14:58:05
【问题描述】:

我正在使用 SQLite-Net PCL 和 SQLite-Net 扩展来开发使用 Xamarin 的应用程序。

我有两个类 AB 定义如下:

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 不应该替换对象吗?

【问题讨论】:

标签: sqlite xamarin sqlite-net sqlite-net-extensions


【解决方案1】:

我检查了该行的提交,现在我记得:似乎AutoIncrement 主键仅适用于Insert 语句,不适用于InsertOrReplace。因此,如果您调用 InsertOrReplace 并将 AutoIncrement 主键设置为 0,它将始终覆盖数据库中 ID 为 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;
    }
}

希望对你有帮助。

【讨论】:

  • 感谢您的帮助。实际上,我正在研究一种比这个更复杂的数据模型,所以每次插入时,我都会检查对象是否已经存在。老实说,我遇到了另一个更奇怪的问题,不幸的是我没能用一个更小的例子来重现,但我也找到了解决方法。
  • 此外,我认为您的示例将与 InsertOrReplaceWithChildren 一起使用,并且它会正确分配 ID,这也是造成混淆的原因
猜你喜欢
  • 1970-01-01
  • 2019-04-16
  • 1970-01-01
  • 1970-01-01
  • 2011-01-27
  • 1970-01-01
  • 2017-01-06
  • 1970-01-01
  • 2011-07-25
相关资源
最近更新 更多