我从webservice获取了一个对象列表。数据应存储在SQLite数据库中。因此,我可以使用InsertWithChildrenAsync()
将第一项存储在数据库中,第二项我得到一个异常,应用程序崩溃。
班级定义:
public class Color
{
[PrimaryKey]
public string Code { get; set; }
public string Name { get; set; }
}
public class Person
{
[PrimaryKey]
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey(typeof(Color))]
public string FavoriteColorId { get; set; }
[OneToOne(CascadeOperations = CascadeOperation.All)]
public Color FavoriteColor { get; set; }
}
初始化:
var dbPath = DependencyService.Get<IStorageService>().GetFilePathForDB();
DependencyService.Get<IStorageService>().DeleteFile(dbPath);
var db = new SQLiteAsyncConnection(dbPath);
await db.CreateTableAsync<Color>();
await db.CreateTableAsync<Person>();
演示此问题的代码:
var pers1 = new Person()
{
Id = 1,
Name = "John",
FavoriteColor = new Color() { Code = "FF0000", Name = "Red" }
};
var pers2 = new Person()
{
Id = 2,
Name = "Doe",
FavoriteColor = new Color() { Code = "FF0000", Name = "Red" }
};
await db.InsertWithChildrenAsync(pers1, true);
await db.InsertWithChildrenAsync(pers2, true);
错误消息
SQLite.SQLiteException:Constraint
如果我使用
,则不会发生这种情况var pers2 = new Person()
{
Id = 2,
Name = "Doe",
FavoriteColor = new Color() { Code = "00FF00", Name = "Green" }
};
问题是两次插入相同的主键。一种解决方案是使用自动增量,但随后将多次存储相同的数据。如何为不同的对象使用相同的数据?来自Web服务的数据被解析并随后存储在数据库中。我不会一直把对象留在内存中。否则我可以使用像
这样的东西Color red = new Color { Code = "00FF00", Name = "Green" };
pers1.FavoriteColor = red;
pers2.FavoriteColor = red;
我需要一张多对多的桌子吗?删除怎么样?目前,我打算使用DeleteAsync()
,但不能完全删除该条目,因为另一个实例正在使用它。该方法是否考虑到了这一点?
我有什么选择?
答案 0 :(得分:1)
您要插入此对象两次:
new Color() { Code = "00FF00", Name = "Green" }
因此,您正在获取主键约束错误。我建议你在将它插入数据库之前检查是否存在该元素。
答案 1 :(得分:0)
如果您有像我这样的复杂数据结构,您可以执行以下操作:不使用自动增量标记[PrimaryKey, AutoIncrement]
的主键必须单独处理。
对于插入,请勿使用CascadeOperations = CascadeOperation.CascadeInsert
。相反,您必须手动插入它们。 E.g。
await StoreColorAsync(db, red);
await db.InsertWithChildrenAsync(pers1, false);
public async Task StoreColorAsync(SQLiteAsyncConnection db, Color color)
{
if (color == null)
return;
var foundItem = await GetColorAsync(db, color.Code);
if (foundItem != null)
{
await db.UpdateAsync(color);
}
else
{
await db.InsertAsync(color);
}
}
public async Task<Color> GetColorAsync(SQLiteAsyncConnection db, string colorCode)
{
var queryResult = await db.Table<Color>().Where(c => c.Code == colorCode).CountAsync();
if (queryResult > 0)
{
return await db.GetAsync<Color>(colorCode);
}
else
{
return null;
}
}
对于删除,仅对具有自动增量标记的条目使用CascadeOperations = CascadeOperation.CascadeDelete
。在这里,我将其他条目留在数据库中,以后可能会重复使用。在某些特殊事件(例如注销)中,我清除了所有表格。