Xamarin Forms SQLite是否有EF中CurrentValues.SetValues的等效更新方式?
在Xamarin Forms中使用SQLite仅更新模型特定字段
你当前的更新方式会把未赋值的字段设为null,这是因为UpdateAsync会将传入的实体完整覆盖到数据库中。下面提供几种解决思路,实现仅更新指定字段:
方法1:先查询再更新(最直观)
先从数据库取出目标实体,只修改需要更新的字段,再执行更新操作,这样未修改的字段会保留原有值:
// 先获取数据库中已存在的实体 var existingAuth = await validateToken.GetById(defaultUser.pid); // 仅更新需要修改的字段 existingAuth.defaultUser = "N"; // 执行更新 await validateToken.Update(existingAuth); // 你的Update方法无需修改 public async Task<int> Update(T entity) { return await db.UpdateAsync(entity); }
方法2:直接执行原生SQL语句(性能最优)
跳过实体操作,直接编写Update语句指定要更新的字段和条件,避免额外的查询开销:
// 新增一个针对性的更新方法 public async Task<int> UpdateDefaultUser(int pid, string defaultUserValue) { string updateSql = "UPDATE Auth SET defaultUser = ? WHERE pid = ?"; return await db.ExecuteAsync(updateSql, defaultUserValue, pid); } // 调用方式 await validateToken.UpdateDefaultUser(defaultUser.pid, "N");
方法3:通过反射自动忽略Null属性(自动化处理)
如果想保留你原来的实体传入方式,可以写一个工具方法,自动将传入实体中Null的属性替换为数据库中现有实体的对应值:
// 扩展方法,用于合并现有实体和更新实体的属性 public static async Task<T> MergeWithExistingAsync<T>(this SQLiteAsyncConnection db, T updatedEntity) where T : class, new() { // 这里假设实体的主键是pid,需根据你的实际主键调整 var primaryKeyProp = typeof(T).GetProperty("pid"); if (primaryKeyProp == null) throw new InvalidOperationException("实体未找到主键属性pid"); var primaryKeyValue = primaryKeyProp.GetValue(updatedEntity); var existingEntity = await db.FindAsync<T>(primaryKeyValue); // 遍历所有属性,将更新实体中为Null的属性替换为现有实体的值 foreach (var prop in typeof(T).GetProperties()) { var updatedValue = prop.GetValue(updatedEntity); if (updatedValue == null) { prop.SetValue(updatedEntity, prop.GetValue(existingEntity)); } } return updatedEntity; } // 调用方式 var updatedAuth = new Auth { pid = defaultUser.pid, defaultUser = "N" }; updatedAuth = await db.MergeWithExistingAsync(updatedAuth); await validateToken.Update(updatedAuth);
各方法对比
- 方法1:简单易维护,适合字段较少的场景,但需要额外一次数据库查询。
- 方法2:性能最高,无额外查询,但需要手动编写SQL,缺乏类型安全。
- 方法3:无需手动处理每个字段,自动化程度高,但反射会带来轻微性能损耗。
内容的提问来源于stack exchange,提问作者vcargo
相关产品推荐
相关产品推荐

