EF核心从数据库强制刷新实体(从数据库强制获取值)

时间:2018-08-10 11:07:02

标签: sql-server .net-core decimal entity-framework-core precision

我想了解如何使用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,29,但始终保持1,2888。我已经在数据库中查询了值,它是1,29,下一个请求也将返回1,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

1 个答案:

答案 0 :(得分:0)

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

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

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

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

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

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

但是,如果您确实需要将此行保存回来,则此方法可能会导致管理混乱或丢失更改的风险。