You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中实现类SQL触发器的事件监听功能?

实现C#实体属性变更的事件监听(类SQL触发器功能)

要实现类似SQL触发器的属性变更自动记录功能,核心思路是利用.NET的INotifyPropertyChanged接口,让实体属性变更时自动触发事件,再通过统一的监听类处理变更记录插入,彻底避免重复调用记录方法。以下是具体实现方案:

1. 封装实体基类(实现属性变更通知)

先写一个通用基类,所有需要监控的实体都继承它,避免重复编写变更通知逻辑:

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Collections.Generic;

public class BaseEntity : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    // 触发属性变更事件的通用方法
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    // 通用属性赋值方法,值变化时自动触发事件
    protected bool SetProperty<T>(ref T backingField, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(backingField, value))
            return false;

        backingField = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}

[CallerMemberName]特性会自动获取调用该方法的属性名,不用手动传入,简化代码。

2. 编写业务实体类

以用户实体为例,所有需要监控的属性都通过基类的SetProperty方法赋值:

public class User : BaseEntity
{
    private string _userName;
    private int _age;

    public string UserName
    {
        get => _userName;
        set => SetProperty(ref _userName, value);
    }

    public int Age
    {
        get => _age;
        set => SetProperty(ref _age, value);
    }

    // 可选:如果需要记录具体实体ID,添加主键属性
    public int Id { get; set; }
}

3. 实现变更记录监听类

这个类负责订阅实体的变更事件,统一处理数据库插入逻辑:

public class EntityChangeMonitor
{
    private readonly YourDbContext _dbContext;

    // 构造函数注入数据上下文(比如EF Core的DbContext)
    public EntityChangeMonitor(YourDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    // 订阅实体的变更事件
    public void Subscribe(BaseEntity entity)
    {
        entity.PropertyChanged += HandlePropertyChanged;
    }

    // 取消订阅(避免内存泄漏,实体销毁前调用)
    public void Unsubscribe(BaseEntity entity)
    {
        entity.PropertyChanged -= HandlePropertyChanged;
    }

    private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        var entity = sender as BaseEntity;
        if (entity == null || string.IsNullOrEmpty(e.PropertyName))
            return;

        // 通过反射获取属性新值
        var property = entity.GetType().GetProperty(e.PropertyName);
        var newValue = property?.GetValue(entity)?.ToString();

        // 构造变更记录并插入数据库
        var changeLog = new ChangeLog
        {
            EntityType = entity.GetType().Name,
            EntityId = (entity as User)?.Id ?? 0, // 替换为你的实体主键逻辑
            PropertyName = e.PropertyName,
            NewValue = newValue,
            ChangeDate = DateTime.Now
        };

        _dbContext.ChangeLogs.Add(changeLog);
        _dbContext.SaveChanges();
    }
}

// 变更记录实体(对应数据库表)
public class ChangeLog
{
    public int Id { get; set; }
    public string EntityType { get; set; }
    public int EntityId { get; set; }
    public string PropertyName { get; set; }
    public string NewValue { get; set; }
    public DateTime ChangeDate { get; set; }
}

4. 实际使用示例

在创建实体后订阅监听,之后所有属性变更都会自动触发记录:

// 初始化数据上下文和监听类
var dbContext = new YourDbContext();
var changeMonitor = new EntityChangeMonitor(dbContext);

// 创建实体并订阅
var user = new User { Id = 1, UserName = "old_name" };
changeMonitor.Subscribe(user);

// 任意更新属性,自动插入变更记录
user.UserName = "new_name";
user.Age = 30;

// 实体不再使用时取消订阅(可选,避免内存泄漏)
// changeMonitor.Unsubscribe(user);

优化建议

  • 批量保存:如果属性变更频繁,可在监听类中缓存变更记录,定时或在业务操作结束后批量调用SaveChanges,提升性能。
  • 属性过滤:可在基类或监听类中添加逻辑,只监控指定属性(比如通过特性标记),排除不需要记录的属性。
  • 泛型扩展:写个泛型扩展方法简化订阅,比如user.SubscribeToChanges(changeMonitor)。

内容的提问来源于stack exchange,提问作者john_boy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 17:42:36