首页
/ FreeSql 中 Repository.InsertOrUpdate 方法触发两次 AuditValue 事件的分析与解决方案

FreeSql 中 Repository.InsertOrUpdate 方法触发两次 AuditValue 事件的分析与解决方案

2025-06-14 04:40:52作者:农烁颖Land

问题背景

在使用 FreeSql 这个强大的 .NET ORM 框架时,开发者可能会遇到审计事件(AuditValue)被意外触发多次的情况。特别是在使用 Repository 模式的 InsertOrUpdate 方法时,当执行更新操作时,AuditValue 事件会被连续触发两次,这显然不符合预期行为。

问题现象

通过一个简单的代码示例可以重现这个问题:

// 定义实体类
public class People
{
    [Column(IsPrimary = true, IsIdentity = true)]
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
}

// 配置 FreeSql 并监听 AuditValue 事件
var freeSql = new FreeSqlBuilder()
    .UseConnectionString(DataType.Sqlite, "Data Source=:memory:")
    .UseAutoSyncStructure(true)
    .Build();

freeSql.Aop.AuditValue += (_, args) => {
    Console.WriteLine(args.AuditValueType);
    Console.WriteLine(args.Property.Name);
};

// 使用 Repository 进行插入和更新
var repository = freeSql.GetRepository<People>();
var people = new People { Name = "John Doe" };
await repository.InsertOrUpdateAsync(people); // 正常触发一次
people.Name = "Tim Doe";
await repository.InsertOrUpdateAsync(people); // 会触发两次 AuditValue 事件

在第二次调用 InsertOrUpdateAsync 方法时,AuditValue 事件会被触发两次,分别针对 Id 和 Name 属性。

技术分析

1. AuditValue 事件的作用

AuditValue 事件是 FreeSql 提供的一个审计机制,它允许开发者在实体属性值被访问或修改时进行拦截和处理。这个机制常用于实现审计日志、数据校验、自动填充等场景。

2. InsertOrUpdate 方法的内部机制

Repository 的 InsertOrUpdate 方法是一个便捷的方法,它会根据实体是否已存在来自动决定执行插入还是更新操作。在内部实现上:

  1. 首先会检查实体是否已存在(通常通过主键判断)
  2. 如果存在,则执行更新操作
  3. 如果不存在,则执行插入操作

3. 问题根源

经过分析,问题出在更新操作的处理逻辑上。在更新实体时,FreeSql 会:

  1. 首先获取原始实体值(触发一次 AuditValue)
  2. 然后设置新值(再次触发 AuditValue)

这就导致了 AuditValue 事件被意外触发了两次。

解决方案

FreeSql 开发团队已经修复了这个问题。修复方案主要包括:

  1. 优化了 Repository 的 InsertOrUpdate 方法的内部实现
  2. 确保在更新操作时只触发一次 AuditValue 事件
  3. 保持与直接使用 UpdateAsync 方法一致的行为

最佳实践

为了避免类似问题,建议开发者:

  1. 确保使用最新版本的 FreeSql
  2. 在审计事件处理逻辑中考虑幂等性
  3. 对于关键业务逻辑,考虑使用事务确保数据一致性
  4. 在复杂的审计场景中,可以结合其他 AOP 机制如 AuditEntity 来实现更精细的控制

总结

FreeSql 作为一款功能丰富的 ORM 框架,提供了强大的数据访问能力。Repository 模式的 InsertOrUpdate 方法虽然方便,但在早期版本中存在 AuditValue 事件被多次触发的问题。通过理解其内部机制和更新到最新版本,开发者可以避免这个问题,充分利用 FreeSql 提供的各种特性来构建健壮的应用程序。

登录后查看全文
热门项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
22
6
docsdocs
OpenHarmony documentation | OpenHarmony开发者文档
Dockerfile
162
2.05 K
nop-entropynop-entropy
Nop Platform 2.0是基于可逆计算理论实现的采用面向语言编程范式的新一代低代码开发平台,包含基于全新原理从零开始研发的GraphQL引擎、ORM引擎、工作流引擎、报表引擎、规则引擎、批处理引引擎等完整设计。nop-entropy是它的后端部分,采用java语言实现,可选择集成Spring框架或者Quarkus框架。中小企业可以免费商用
Java
8
0
openGauss-serveropenGauss-server
openGauss kernel ~ openGauss is an open source relational database management system
C++
146
191
leetcodeleetcode
🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解
Java
60
16
ohos_react_nativeohos_react_native
React Native鸿蒙化仓库
C++
198
279
apintoapinto
基于golang开发的网关。具有各种插件,可以自行扩展,即插即用。此外,它可以快速帮助企业管理API服务,提高API服务的稳定性和安全性。
Go
22
0
RuoYi-Vue3RuoYi-Vue3
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
950
556
ShopXO开源商城ShopXO开源商城
🔥🔥🔥ShopXO企业级免费开源商城系统,可视化DIY拖拽装修、包含PC、H5、多端小程序(微信+支付宝+百度+头条&抖音+QQ+快手)、APP、多仓库、多商户、多门店、IM客服、进销存,遵循MIT开源协议发布、基于ThinkPHP8框架研发
JavaScript
96
15
Cangjie-ExamplesCangjie-Examples
本仓将收集和展示高质量的仓颉示例代码,欢迎大家投稿,让全世界看到您的妙趣设计,也让更多人通过您的编码理解和喜爱仓颉语言。
Cangjie
346
1.33 K