首页 > 解决方案 > Entity Framework Core - 如何使用通用方法在 SaveChanges 期间动态记录相关实体属性更改?

问题描述

我最近正在围绕 Audit ChangeLog 部分学习 EF Core,在那里我发现大多数资源仅通过使用反射将日志作为实体的直接属性进行跟踪,假设我有两个相关实体:

public Class Order
{
    public int OrderId {get; set;}
    public int OrderName {get; set;}
    public virtual Collection<OrderDetail> OrderDetails { get; set; } = new Collection<OrderDetail>();
}
public Class OrderDetail
{
    public int OrderDetailId {get; set;}
    public int OrderDetailName {get; set;}
    public int OrderDetailQuantity {get; set;}
    public int? OrderID { get; set; }
    public virtual Order OrderFk { get; set; }
}

然后我的 TrackChange 就像:

protected virtual IEnumerable<ChangeLog> TrackChange()
{
    foreach (var entry in DbContext.ChangeTracker.Entries())
    {  
        var entityType = entry.Entity.GetType();

        foreach (var property in entityType.GetTypeInfo().DeclaredProperties)
        {
            var originalValue = entry.Property(property.Name).OriginalValue;
            var currentValue = entry.Property(property.Name).CurrentValue;

            //Log if originalValue != currentValue 
        }
    }
}

因此,如果我有一个包含 3 个 OrderDetails 的订单,那么我通过更新 OrderDetailQuantity并保存为 Order 来修改Order Name和其中一个 OrderDetail ,TrackChange 将捕获我的 OrderName 更改,因为这是 Order 的一个属性,但是当“entityType 中的属性” .GetTypeInfo().DeclaredProperties" 变为 "OrderDetails",它不够聪明,无法检测到这是“Order”的集合或相关实体,然后在尝试获取 originalValue 时出现异常:

'The property 'OrderDetails' on entity type 'Order' is being accessed using the 'Property' method, but is defined in the model as a navigation property. Use either the 'Reference' or 'Collection' method to access navigation properties.'

我知道我可能可以使用 entry.Collection(property.Name) 进入“OrderDetail”集合,但问题是:我怎么知道当前属性是像 Int/String/Datetime 这样的值类型,而它也可以是相关实体还是当前条目的集合?

关于 TrackChange 及以下的其他想法是我的伪代码想法:

function TrackChange(Entity)
   //Track Base Entity Change
   ...
   //Track Child Entity Change if there is any
   if (Entity.HasChildNode) 
   {
      foreach(ChildEntity of Entity.ChildEntities)
           TrackChange(ChildEntity);
   }
   ...
}

因为我的 TrackChange 是通用的,所以我希望有一种方法可以使用 C# 反射来实现上述想法。

标签: c#genericsreflectionentity-framework-coresavechanges

解决方案


推荐阅读