Xamarin sqlite-net-pcl:如何将Task返回值转为实体类对象
解决SQLite异步操作Task转实体及HTTP数据更新问题
首先我得先指出你代码里的几个小语法问题,这些问题会导致代码无法正常运行:
MyDB的构造函数缺少实现逻辑,需要初始化SQLiteAsyncConnection实例SaveMyObjectAsync方法里的InsertAsync语句末尾漏了分号- 参数名
object是C#关键字,得改成myObj这类合法名称 MyObject里的SomeID是int类型,不需要加[MaxLength(20)]特性(这个特性是给字符串类型用的)
先贴出修正后的MyDB类:
public class MyDB { readonly SQLiteAsyncConnection database; // 修正构造函数,初始化数据库连接 public MyDB(string dbPath) { database = new SQLiteAsyncConnection(dbPath); database.CreateTableAsync<MyObject>().Wait(); } public Task<List<MyObject>> GetMyObjectAsync() { return database.Table<MyObject>().ToListAsync(); } public Task<MyObject> GetSingleObjectAsync(int ind) { return database.Table<MyObject>().Where(i => i.IndexNumber == ind).FirstOrDefaultAsync(); } // 修正参数名和语法错误 public Task<int> SaveMyObjectAsync(MyObject myObj) { if (myObj.IndexNumber == 0) { return database.InsertAsync(myObj); // 补充分号 } else { return database.UpdateAsync(myObj); } } public Task<int> DeleteMyObjectAsync(MyObject myObj) { return database.DeleteAsync(myObj); } }
接下来解决你核心的两个问题:
1. 从Task获取实体对象(正确处理异步操作)
所有SQLite异步方法返回的都是Task<T>类型,你需要用async/await关键字来获取实际的实体对象,不能直接操作Task本身。而且在UI线程里绝对不能用.Wait()或者.Result,会导致界面卡顿甚至死锁,一定要用await。
举个在XAML页面代码后台获取并操作实体的例子:
private async void LoadAndUpdateObject(int targetIndex) { // 初始化数据库实例(实际项目里建议单例管理,不要每次都new) var db = new MyDB("你的数据库文件路径"); // 用await等待异步操作完成,拿到实体对象 MyObject targetObj = await db.GetSingleObjectAsync(targetIndex); if (targetObj != null) { // 这里就可以直接操作实体的属性了 targetObj.SomeName = "从HTTP更新的名称"; targetObj.Telephone = "从HTTP拿到的手机号"; // 保存回数据库 await db.SaveMyObjectAsync(targetObj); } }
如果是在MVVM模式的ViewModel里,写法类似:
public async Task SyncObjectWithHttp(int index, string newName) { var db = new MyDB("你的数据库路径"); var targetObj = await db.GetSingleObjectAsync(index); if (targetObj != null) { targetObj.SomeName = newName; await db.SaveMyObjectAsync(targetObj); } }
2. 利用HTTP响应数据更新数据库对象
针对你说的“首次仅返回ID和状态码,后续返回其他字段”的场景,可以分两种情况处理:
情况1:根据HTTP返回的ID匹配数据库对象并更新
private async void UpdateObjectFromHttp(int httpReturnedId, string newName, string newPhone) { var db = new MyDB("你的数据库路径"); // 假设用SomeID匹配数据库里的对象(如果是用IndexNumber匹配就用GetSingleObjectAsync) var targetObj = await database.Table<MyObject>().Where(o => o.SomeID == httpReturnedId).FirstOrDefaultAsync(); if (targetObj != null) { // 更新从HTTP拿到的字段 targetObj.SomeName = newName; targetObj.Telephone = newPhone; targetObj.someTime = DateTime.Now; // 保存到数据库 await db.SaveMyObjectAsync(targetObj); } }
情况2:HTTP返回完整对象数据,插入或更新
如果后续请求返回了完整的对象数据,可以先检查数据库是否已有该对象,不存在就插入,存在就更新:
private async void SyncHttpObjectToDb(MyObject httpObj) { var db = new MyDB("你的数据库路径"); // 检查数据库中是否存在该对象 var existingObj = await db.GetSingleObjectAsync(httpObj.IndexNumber); if (existingObj == null) { // 新对象,重置IndexNumber让InsertAsync生效 httpObj.IndexNumber = 0; await db.SaveMyObjectAsync(httpObj); } else { // 更新已有对象的所有字段 existingObj.SomeID = httpObj.SomeID; existingObj.SomeName = httpObj.SomeName; existingObj.Telephone = httpObj.Telephone; existingObj.someTime = httpObj.someTime; await db.SaveMyObjectAsync(existingObj); } }
最后提个小建议:MyObject里的someTime字段首字母最好改成大写(符合C#命名规范),改成SomeTime,这样代码可读性会更好。
内容的提问来源于stack exchange,提问作者Kael Tharas
相关产品推荐
相关产品推荐

