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

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

2025-06-14 12:52:54作者:农烁颖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 提供的各种特性来构建健壮的应用程序。

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

热门内容推荐

最新内容推荐

项目优选

收起
openHiTLS-examplesopenHiTLS-examples
本仓将为广大高校开发者提供开源实践和创新开发平台,收集和展示openHiTLS示例代码及创新应用,欢迎大家投稿,让全世界看到您的精巧密码实现设计,也让更多人通过您的优秀成果,理解、喜爱上密码技术。
C
52
461
kernelkernel
deepin linux kernel
C
22
5
openHiTLSopenHiTLS
旨在打造算法先进、性能卓越、高效敏捷、安全可靠的密码套件,通过轻量级、可剪裁的软件技术架构满足各行业不同场景的多样化要求,让密码技术应用更简单,同时探索后量子等先进算法创新实践,构建密码前沿技术底座!
C
349
381
nop-entropynop-entropy
Nop Platform 2.0是基于可逆计算理论实现的采用面向语言编程范式的新一代低代码开发平台,包含基于全新原理从零开始研发的GraphQL引擎、ORM引擎、工作流引擎、报表引擎、规则引擎、批处理引引擎等完整设计。nop-entropy是它的后端部分,采用java语言实现,可选择集成Spring框架或者Quarkus框架。中小企业可以免费商用
Java
7
0
openGauss-serveropenGauss-server
openGauss kernel ~ openGauss is an open source relational database management system
C++
131
185
RuoYi-Vue3RuoYi-Vue3
🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统
Vue
873
517
Cangjie-ExamplesCangjie-Examples
本仓将收集和展示高质量的仓颉示例代码,欢迎大家投稿,让全世界看到您的妙趣设计,也让更多人通过您的编码理解和喜爱仓颉语言。
Cangjie
336
1.09 K
ohos_react_nativeohos_react_native
React Native鸿蒙化仓库
C++
179
264
cherry-studiocherry-studio
🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端
TypeScript
608
59
note-gennote-gen
一款跨平台的 Markdown AI 笔记软件,致力于使用 AI 建立记录和写作的桥梁。
TSX
83
4