EF Core - 如何使用值对象审计跟踪

2024-02-02

我正在尝试对 Entity Framework Core 中选择的类实现审计跟踪(跟踪更改内容、更改时间和更改者)。

我当前的实现依赖于覆盖 SaveChangesAsync:

public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default) 
{
    var currentUserFullName = _userService.CurrentUserFullName!;

    foreach (var entry in ChangeTracker.Entries<AuditableEntity>())  
    {
        switch (entry.State) 
        {
            case EntityState.Added:
                    entry.Entity.CreatedBy = currentUserFullName;
                    entry.Entity.Created = _dateTime.Now;
                    break;

            case EntityState.Modified:
                    var originalValues = new Dictionary<string, object?>();
                    var currentValues = new Dictionary<string, object?>();

                    foreach (var prop in entry.Properties.Where(p => p.IsModified)) 
                    {
                        var name = prop.Metadata.Name;
                        originalValues.Add(name, prop.OriginalValue);
                        currentValues.Add(name, prop.CurrentValue);
                    }
                    entry.Entity.LastModifiedBy = currentUserFullName;
                    entry.Entity.LastModified = _dateTime.Now;

                    entry.Entity.LogEntries.Add(
                        new EntityEvent(
                            _dateTime.Now,
                            JsonConvert.SerializeObject(originalValues),
                            JsonConvert.SerializeObject(currentValues),
                            currentUserFullName));
                    break;
            }
        }

        return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}

这简单、干净并且非常容易使用;任何需要审计跟踪的实体只需要继承AuditableEntity.

然而,这种方法有一个严重的限制:它无法捕获对导航属性所做的更改。

我们的实体充分利用值对象,例如电子邮件地址:

public class EmailAddress : ValueObjectBase
{
    public string Value { get; private set; } = null!;

    public static EmailAddress Create(string value) 
    {
        if (!IsValidEmail(value)) 
        {
            throw new ArgumentException("Incorrect email address format", nameof(value));
        }

        return new EmailAddress {
            Value = value
        };
    }
}

... Entity.cs

public EmailAddress Email { get; set; }   

... Entity EF configuration
entity.OwnsOne(e => e.Email);

... Updating
entity.Email = EmailAddress.Create("[email protected] /cdn-cgi/l/email-protection");

现在,如果用户更改该实体的电子邮件地址,该实体的状态永远不会更改为已修改。 EF Core 似乎将 ValueObjects 作为导航属性来处理,它们是单独处理的。

所以我认为有几个选择:

  1. 停止使用 ValueObject 作为实体属性。我们仍然可以将它们用作实体构造函数参数,但这会导致其余代码的级联复杂性。它还会降低对数据有效性的信任。

  2. 停止使用 SaveChangesAsync 并构建我们自己的审核处理。同样,这会导致架构进一步复杂,并且可能会降低性能。

  3. ChangeTracker 的一些奇怪的黑客行为 - 这听起来有风险,但理论上可能有效

  4. 还有什么,什么?


如果您将值对象映射到数据库中的单个列(例如,电子邮件地址存储在文本列中),您可能可以使用转换器:

var emailAddressConverter = new ValueConverter<EmailAddress, string>(
    emailAddress => emailAddress.Value,
    @string => EmailAddress.Create(@string));

modelBuilder.Entity<User>()
    .Property(user => user.Email)
    .HasConversion(emailAddressConverter);

这应该与您的更改跟踪代码配合良好。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

EF Core - 如何使用值对象审计跟踪 的相关文章

  • 如何将 std::string& 转换为 C# 引用字符串

    我正在尝试将 C 函数转换为std string参考C 我的 API 如下所示 void GetStringDemo std string str 理想情况下 我希望在 C 中看到类似的东西 void GetStringDemoWrap r
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • 机器Epsilon精度差异

    我正在尝试计算 C 中双精度数和浮点数的机器 epsilon 值 作为学校作业的一部分 我在 Windows 7 64 位中使用 Cygwin 代码如下 include
  • std::vector 与 std::stack

    有什么区别std vector and std stack 显然 向量可以删除集合中的项目 尽管比列表慢得多 而堆栈被构建为仅后进先出的集合 然而 堆栈对于最终物品操作是否更快 它是链表还是动态重新分配的数组 我找不到关于堆栈的太多信息 但
  • 随着时间的推移,添加到 List 变得非常慢

    我正在解析一个大约有 1000 行的 html 表 我从一个字符串中添加 10 个字符串 td 每行到一个list td
  • 为什么 GCC 不允许我创建“内联静态 std::stringstream”?

    我将直接前往 MCVE include
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • 如何从本机 C(++) DLL 调用 .NET (C#) 代码?

    我有一个 C app exe 和一个 C my dll my dll NET 项目链接到本机 C DLL mynat dll 外部 C DLL 接口 并且从 C 调用 C DLL 可以正常工作 通过使用 DllImport mynat dl
  • 在 Unity 中实现 Fur with Shells 技术

    我正在尝试在 Unity 中实现皮毛贝壳技术 http developer download nvidia com SDK 10 5 direct3d Source Fur doc FurShellsAndFins pdf Fins 技术被
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • 为什么 C# 2.0 之后没有 ISO 或 ECMA 标准化?

    我已经开始学习 C 并正在寻找标准规范 但发现大于 2 0 的 C 版本并未由 ISO 或 ECMA 标准化 或者是我从 Wikipedia 收集到的 这有什么原因吗 因为编写 审查 验证 发布 处理反馈 修订 重新发布等复杂的规范文档需要
  • C 编程:带有数组的函数

    我正在尝试编写一个函数 该函数查找行为 4 列为 4 的二维数组中的最大值 其中二维数组填充有用户输入 我知道我的主要错误是函数中的数组 但我不确定它是什么 如果有人能够找到我出错的地方而不是编写新代码 我将不胜感激 除非我刚去南方 我的尝
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • 如何在当前 Visual Studio 主机内的 Visual Studio 扩展中调试使用 Roslyn 编译的代码?

    我有一个 Visual Studio 扩展 它使用 Roslyn 获取当前打开的解决方案中的项目 编译它并从中运行方法 程序员可以修改该项目 我已从当前 VisualStudioWorkspace 成功编译了 Visual Studio 扩
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • 为什么C++代码执行速度比java慢?

    我最近用 Java 编写了一个计算密集型算法 然后将其翻译为 C 令我惊讶的是 C 的执行速度要慢得多 我现在已经编写了一个更短的 Java 测试程序和一个相应的 C 程序 见下文 我的原始代码具有大量数组访问功能 测试代码也是如此 C 的
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • DotNetZip:如何提取文件,但忽略zip文件中的路径?

    尝试将文件提取到给定文件夹 忽略 zip 文件中的路径 但似乎没有办法 考虑到其中实现的所有其他好东西 这似乎是一个相当基本的要求 我缺少什么 代码是 using Ionic Zip ZipFile zf Ionic Zip ZipFile
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri

随机推荐

  • #ifdef DEBUG 与 #if DEBUG

    当使用编译器指令时 我不清楚以下两个代码片段中哪一个是正确 首选以及原因 似乎我见过的大多数开发人员和开源项目都使用第一个 但我也看到第二个也经常使用 ifdef DEBUG self doSomethingOnlyWhenDebuggin
  • 为什么应该使用基于文档的数据库而不是关系数据库?

    为什么我应该使用基于文档的数据库 如 CouchDB 而不是使用关系数据库 是否存在基于文档的数据库比关系数据库更适合的典型应用程序或领域 也许你不应该 第二个最明显的答案是 如果您的数据不相关 则应该使用它 这通常表现为没有简单的方法将数
  • Vertx JDBC 客户端 queryWithParams - 如何添加列表?

    我有带条件的 SQL 查询currency in 我正在使用 vertx JDBC 客户端queryWithparams方法 它接收 JsonArray 中的查询参数 我怎样才能传递我的可能列表currency查询的值 我试过new Jso
  • 购物车 $_SESSION 问题

    我正在开发一个基本的购物车 但是 SESSION 变量似乎未正确存储或访问 例如 如果您前往它将显示项目名称 但是在没有任何 GET 变量的情况下刷新 cart php 时 它不会返回任何内容 我究竟做错了什么
  • 如何使用javascript或html打开手机chrome浏览器

    我有两个问题 我要这个 我想使用 javascript 或 html 在其他 Android 移动网络应用程序 例如 naver firefox 等 上打开带有 url 的 chrome 浏览器 所以例子 如果用户在移动网络应用程序上单击
  • 在一台机器上运行多个 MySQL 服务器

    我们可以在一台机器上运行多个 MySQL 服务器吗 Thanks 是的 您只需在单独的端口上运行它们并将它们指向不同的 lib 目录以获取其数据 这是一个很好的参考 http dev mysql com doc refman 5 1 en
  • ASP.NET C# 大文件上传时出现 OutofMemoryException

    我有以下文件上传处理程序 public class FileUploader IHttpHandler public void ProcessRequest HttpContext context HttpRequest request c
  • 如何在表过滤器中显示“未找到记录”消息

    我根据两个 tds 在我的桌子上应用过滤器 过滤器正在工作 但如果没有值匹配 我想显示 未找到记录 消息 这是一个示例演示 filter click function var tdScoring tdEarning var scoring
  • AttributeError:“NoneType”对象没有属性“dpi_scale_trans”

    通过 StackOverflow 检查我遇到的上述错误的可能解决方案后 我发现一些解决方案无法解决这个特定问题 下图显示了尝试在图上绘制多个轴时遇到的错误和获得的不需要的图 This is an image of the expected
  • 错误模板设计

    似乎我在这个网站上读到了关于这个问题的另一个问题 答案 但我不记得答案是什么 现在我找不到原始帖子 我不喜欢 WPF 中的默认错误模板 我了解如何更改此错误模板 但是 如果我将一些内容添加到文本框的末尾 则文本框的大小不会改变 并且添加的内
  • Collections.shuffle() 真的足够随机吗?实际例子似乎否定了这个说法

    我有 1000 个独特的对象java util List 每个都引用一个图像 1000 个列表中的每个图像都是唯一的 现在我想对它们进行洗牌 以便我可以使用前 20 个对象并将它们呈现给网站用户 然后 用户可以单击 随机播放 按钮 然后我再
  • Cordova 应用程序中的触发事件

    我正在尝试触发事件 backbutton pause resume等 从浏览器手动在cordova中 用于调试 我按照以下方式进行 window trigger backbutton 当我们使用注册事件处理程序时 document on b
  • 如何使 Selenium 不等待整个页面加载,其脚本速度很慢?

    硒driver get url 等到整页加载 但是抓取页面会尝试加载一些无效的 JS 脚本 所以我的 Python 脚本等待它并且几分钟后不起作用 这个问题可能出现在网站的每个页面上 from selenium import webdriv
  • Javascript 数组和 Meteor 会话

    我做了一个有趣的观察 当尝试更新存储在 Meteor 会话存储中的数组时 以下代码将不会传播更改 var tags Session get Tags tags push a Session set Tags tags 但是如果我改变第一行来
  • 如何检测 tcp 连接是否已从 ssl 连接转发?

    我正在处理的具体场景是尝试连接到 AWS 弹性负载均衡器后面的 websocket 连接 同时强制使用 https ssl 而不是 http tcp 要启用从 http s 的 TCP SSL 升级 负载均衡器上的协议必须在端口 80 上设
  • 如何防止 NULL 值插入到 Jackson 中的 ObjectNode

    我希望杰克逊在将空值放入 ObjectNode 实例时忽略它们 我知道如何在序列化 pojo 时防止空值 这里我手动将键 值放入 ObjectNode 实例中 并且我希望杰克逊在值为空时忽略要忽略的键 值 例如 objectNode put
  • 从 Android 应用程序使用 OAuth2 访问 Gmail Atom feed 停止工作

    我有一个 Android 应用程序 它可以访问 Gmail Atom 收件箱提要 以只读方式访问未读电子邮件 这就是我所需要的 而且 它最近停止工作了 它正在使用OAuth2 and 谷歌验证工具 这是它的工作原理 在服务中使用 Async
  • 如何让jquery select2动态禁用一个选项?

    我有一些多选 我使用 jquery select2 当在一个多选中选择此选项时 我想禁用其他多选中的一个选项 我写了这段代码 但它确实有效 select multiselect on change function e if e added
  • |1 在 Docker 历史中意味着什么

    鉴于这种Dockerfile FROM debian 8 3 ARG TEST 123 RUN echo TEST 什么是 1在 Docker 历史上有哪些代表 docker history 2feee0d8320f IMAGE CREAT
  • EF Core - 如何使用值对象审计跟踪

    我正在尝试对 Entity Framework Core 中选择的类实现审计跟踪 跟踪更改内容 更改时间和更改者 我当前的实现依赖于覆盖 SaveChangesAsync public override Task