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

问题描述 投票:0回答:2

使用 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 = ?????;
}
c# entity-framework entity-framework-core dbcontext
2个回答
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;
}

要使其动态化,请从

<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
}

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

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; }
}

0
投票

https://github.com/dotnet/efcore/issues/9050

原始值是查询实体时数据库中存在的值。因此对于关系来说,FK属性将具有原始值。导航属性是根据 FK 值合成的,而不是直接映射到数据库中的任何内容。这意味着导航属性(引用和集合)没有原始值。

© www.soinside.com 2019 - 2024. All rights reserved.