I am using SQLite-Net PCL together with SQLite-Net extensions for the development of an application using Xamarin.
I have two classes A
and B
defined as follows:
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;
}
}
I am trying to use insert or replace in the following way:
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);
}
The problem is that the second InsertOrReplaceWithChildren
is throwing a Constraint
exception, that is not thrown if we remove the unique constraint on A.Name
. Isn't InsertOrReplaceWithChildren
supposed to replace the object if a unique constraint is violated?
I checked the commits for that line, now I remember: it seems that the AutoIncrement
primary key only works for Insert
statements and not for InsertOrReplace
. As consequence if you call InsertOrReplace
with an AutoIncrement
primary key set to 0, it will always overwrite the same value in the database with ID 0 instead of correctly adding new values.
This issue is easy to check by executing this test:
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);
To solve it you have to give up either the AutoIncrement
primary key or the Unique
constraint check for the InsertOrReplace
statement to work.
These are drop-in replacement classes that should work as expected giving up the AutoIncrement
primary keys:
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;
}
}
Hope it helps.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.