如何从 Entity Framework Core 中的导航集合属性获取原始值?

Ale*_*bin 6 c# entity-framework dbcontext entity-framework-core

使用 Entity Framework Core,我需要检查实体内导航属性的原始值,但我找不到方法来执行此操作。

我能够读取实际实体的原始值和当前值及其参考属性,但是当我读取导航属性时,OriginalValue 属性丢失了。

这是我到目前为止所能做的。

var entries = ChangeTracker.Entries<Book>()
                .Where(x => x.State == EntityState.Modified)
                .ToList();

foreach (var entry in entries)
{   
   // read the entity current & original values 
   var currentTitleValue = entry.Property(x => x.Title).CurrentValue;
   var originalTitleValue = entry.Property(x => x.Title).OriginalValue;

   // read the reference object current & original values
   var promotionReferenceEntry = entry.Reference(x => x.Promotion);
   var currentPromotionPriceValue = promotionReferenceEntry.TargetEntry.Property(x => x.Price).CurrentValue;
   var originalPromotionPriceValue = promotionReferenceEntry.TargetEntry.Property(x => x.Price).OriginalValue;

   // read the navigation object current & original values
   var authorsCollectionEntry = entry.Collection(x => x.AuthorBooks);
   var currentAuthorIds = authorsCollectionEntry.CurrentValue.Select(x => x.AuthorId).ToList();
   var originalAuthorIds = ?????;
}
Run Code Online (Sandbox Code Playgroud)

Pie*_*rre 1

以下是获取上下文中的引用属性及其原始值的方法:

var entries = ChangeTracker.Entries<Book>()
                .Where(x => x.State == EntityState.Modified)
                .ToList();

foreach (var entry in entries)
{
    // If it is Added/Deleted, you can't get the OriginalValues/CurrentValues respectively.
    // So make it Modified for the meanwhile.
    var tempState = entry.State;
    entry.State = EntityState.Modified;
    
    // Clone the Entity values (the original ID, Current ID of the navigation
    var currentValues = Entry(entry.Entity).CurrentValues.Clone();
    var originalValues = Entry(entry.Entity).OriginalValues.Clone();
    
    // Set the Entity values to the OriginalValues and load the reference
    Entry(entry.Entity).CurrentValues.SetValues(originalValues);
    Entry(entry.Entity).Reference(x => x.Promotion).Load();
    
    // Store the Original Reference value in a variable
    var promotionReferenceEntryOriginalValue = entry.Reference(x => x.Promotion).CurrentValue;
    
    // Set the Entity values back to CurrentValues and load the reference
    Entry(entry.Entity).CurrentValues.SetValues(currentValues);
    Entry(entry.Entity).Reference(x => x.Promotion).Load();
    
    // Store the Current Reference value in a variable
    var promotionReferenceEntryCurrentValue = entry.Reference(x => x.Promotion).CurrentValue;
    
    // Set the Entry State back to its original State Added/Modified/Deleted
    entry.State = tempState;
    
    // read the entity current & original values 
    var currentTitleValue = entry.Property(x => x.Title).CurrentValue;
    var originalTitleValue = entry.Property(x => x.Title).OriginalValue;

    // read the reference object current & original values
    //var promotionReferenceEntry = entry.Reference(x => x.Promotion);
    var currentPromotionPriceValue = promotionReferenceEntryCurrentValue.Price; // promotionReferenceEntry.TargetEntry.Property(x => x.Price).CurrentValue;
    var originalPromotionPriceValue = promotionReferenceEntryOriginalValue.Price; // promotionReferenceEntry.TargetEntry.Property(x => x.Price).OriginalValue;
}
Run Code Online (Sandbox Code Playgroud)

要使其动态化,请<Book>从循环中删除类型ChangeTracker.Entries<Book>()并循环遍历循环entry.Entity内的属性foreach (var entry in entries)

foreach (var propertyInfo in entry.Entity.GetType().GetProperties())
{
    var propertyName = propertyInfo.Name;
    //Do the loads here...
    //Get the values
}
Run Code Online (Sandbox Code Playgroud)

通过尝试使用额外的方法访问它来检查它是否是导航引用或集合引用,并检查它是否为空,不为空意味着它是一个可以尝试的有效属性load()

private DbPropertyEntry GetProperty(DbEntityEntry entry, string propertyName)
{
    try
    {
        return entry.Property(propertyName);
    }
    catch { return null; }
}

private DbReferenceEntry GetReference(DbEntityEntry entry, string propertyName)
{
    try
    {
        return entry.Reference(propertyName);
    }
    catch { return null; }
}

private DbCollectionEntry GetCollection(DbEntityEntry entry, string propertyName)
{
    try
    {
        return entry.Collection(propertyName);
    }
    catch { return null; }
}
Run Code Online (Sandbox Code Playgroud)