gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 09:31:01 24 4
gpt4 key购买 nike

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

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

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 .

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

我们的实体很好地利用了值对象,例如 EmailAddress:
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("e@mail.com");

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

所以我认为有几个选择:
  • 停止使用 ValueObjects 作为实体属性。我们仍然可以将它们用作实体构造函数的参数,但这会导致其余代码的级联复杂性。它还会降低对数据有效性的信任。
  • 停止使用 SaveChangesAsync 并构建我们自己的审计处理。同样,这会导致架构进一步复杂化,并且性能可能会降低。
  • ChangeTracker 的一些奇怪的黑客 - 这听起来有风险,但理论上可能有效
  • 还有什么,什么?
  • 最佳答案

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

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

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

    这应该适用于您的更改跟踪代码。

    关于c# - EF Core - 如何使用值对象审计跟踪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60946496/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com