EF Core 强制刷新数据库中的实体(强制从 DB 提取值)

EF Core force refresh Entity from Database (force fetching values from DB)

提问人:Edub 提问时间:8/10/2018 最后编辑:Edub 更新时间:12/23/2022 访问量:7050

问:

我想了解如何使用 Entity Framework Core 加载/获取实体的当前数据库值(“从数据库强制重新加载”)。 我的属性如下所示:

[Column(TypeName = "decimal(16, 2)")]
public decimal Fee { get; set; }

如果费用的保存精度高于列属性中指定的精度,例如 数据库将其四舍五入到小数点后两位,但我保存的实体没有更新。1,2888

因此,我尝试从数据库中重新加载值以在此UI中显示“正确的当前”值,但以下方法均无效:

// removed from tracked entities and fetch from db
dbContext.Entry(entity).State = EntityState.Detached;
dbContext.Find(...);

// call reload
dbContext.Entry(entity).Reload();

预计该值将在刷新/重新加载之后,但它始终保持不变。我已经在数据库中查找了值,它是,并且下一个请求将返回,但我没有设法在同一请求中返回正确的值。1,291,28881,291,29

有没有办法从数据库中“强制刷新”实体?

---编辑---

问题是我有一个具有导航属性的实体,并且小数点位于导航属性上,调用时未重新加载。Reload() 在实体本身上。

法典

using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

namespace WebApplication1
{
    public class Entity
    {
        public long Id { get; set; }

        public Fee Fee { get; set; }
    }

    public class Fee
    {
        public long Id { get; set; }

        [Column(TypeName = "decimal(16, 2)")]
        public decimal Value { get; set; }
    }


    public class MyContext : DbContext
    {
        public DbSet<Entity> Entities { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder
                .UseSqlServer(@"connectionString");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
        }
    }

    public class Program
    {
        public static void Main()
        {
            AsyncMethod().GetAwaiter().GetResult();
        }

        private static async Task AsyncMethod()
        {
            using (var context = new MyContext())
            {
                context.Database.EnsureDeleted();
                context.Database.EnsureCreated();
            }

            using (var context = new MyContext())
            {
                var entity = new Entity {Fee = new Fee {Value = 12.3456789m}};
                context.Add(entity);
                await context.SaveChangesAsync();
                Console.WriteLine($"Fee value after SaveChanges() {entity.Fee.Value}");
                await context.Entry(entity).ReloadAsync();
                Console.WriteLine($"Fee value after Reload() {entity.Fee.Value}");
            }

            using (var context = new MyContext())
            {
                var entity = await context.Entities.OrderByDescending(x => x.Id).Include(x => x.Fee).FirstAsync();
                Console.WriteLine($"Fee value after Disposing and Recreating Context {entity.Fee.Value}");
            }

        }
    }
}

输出:

Fee value after SaveChanges() 12,3456789
Fee value after Reload() 12,3456789
Fee value after Disposing and Recreating Context 12,35
sql-server .net-core 十进制 实体框架核心 精度

评论

0赞 Panagiotis Kanavos 8/10/2018
EF Core 不缓存任何内容。无需尝试“更新”相同的实体对象,只需再次加载数据并将 UI 绑定到新数据即可。
0赞 Edub 8/10/2018
实际上,我提供了一个API,UI从这个API获取数据。我的用例是我想修补模型并返回“当前值”。因此,我对此请求只有一个 DbContext,据我所知,EF Core 仅为此实体加载一次数据(Identity Map Pattern - stackoverflow.com/a/3653392/732846)。
0赞 Panagiotis Kanavos 8/10/2018
否,EF Core 始终按照你的指示执行操作。它不会缓存或“修补”实体,每次您告诉它时都会加载它们。它每次加载的实体是不同的,即使使用相同的 ID 来加载它们。
7赞 Ivan Stoev 8/10/2018
@PanagiotisKanavos 这绝对不是真的。如果跟踪实体,EF Core 将返回相同的实例(包含缓存的数据),即使它首先查询数据库也是如此。基本上,客户获胜的策略。
1赞 Edub 8/10/2018
只需设置一个只有一个类的空项目并尝试重现它。在这个项目中,它按预期工作。到目前为止,谢谢 - 我需要重现它以提供更好的描述。SaveChanges() 后的费用价值 12,3456789 Reload() 后的费用价值 12,35 处置和重新创建上下文后的费用价值 12,35

答:

0赞 Simon_Weaver 3/31/2021 #1

在有限情况下可能的解决方案

如果您只需要加载数据而不需要维护对象的整个上下文,有时可能是一种解决方案。https://learn.microsoft.com/en-us/ef/core/querying/trackingAsNoTracking

例如,我刚刚有一个案例,我需要:

  • 加载单行
  • 启动挂火任务(在其自己的上下文中运行)
  • 在原始方法中几秒钟后检查状态

通过使用,我能够加载同一行两次,并且看不到任何缓存内容。AsNoTracking

var shipmentData = await context.Shipments.AsNoTracking().Single(s => s.ShipmentId == shipmentId);

但是,如果您确实需要将此行保存回去,则此方法可能会使管理变得混乱,否则可能会丢失更改。

-1赞 Carthorn 12/23/2022 #2

另一种选择是使用 .context.ChangeTracker.Clear();

这会清除所有本地缓存/跟踪的更改,因此请注意这样做。

如果您只想删除一个实体,那么context.ChangeTracker.Context.Remove(myEntity)

评论

0赞 Stephane 1/25/2023
“删除”将从数据库中删除实体,而不是跟踪器。