EF Core 3.1 get data that updated out of the DbContext

Mahfoud Bouabdallah 26 Reputation points
2021-08-05T08:53:07.047+00:00

I have this code in my "Department Form"

        private readonly SIMContext _SIMContext;
        private Department model;
        public Frm_Department(SIMContext SIMContext)
        {
            InitializeComponent();
            _SIMContext = SIMContext;
        }

And this is the method that get data from database I added to load event
I have BindingSource component "dataBindingSource" that assign to gridControl DataSource

    private async Task LoadDataAsync()
    {
            // Call the LoadAsync method to asynchronously get the data for the given DbSet from the database.
            await _SIMContext.Departments.LoadAsync().ContinueWith(loadTask =>
            {
                // Bind data to control when loading complete
                dataBindingSource.DataSource = _SIMContext.Departments.Local.ToBindingList();
            }, TaskScheduler.FromCurrentSynchronizationContext());

    }

all my CRUD operations work fine (using DbContext).
Now to the problem:
If I add records directly(Manually) to the database (not using DbContext) and if I call LoadDataAsync method I get all records without any problem.
But when I edit or remove any record(Manually) (not using DbContext) and then call LoadDataAsync method I get old values not updated one.
How can I resolve this problem?.
I try:

dataBindingSource.ResetBindings(false);
var state = _SIMContext.Entry(model).State;
state = EntityState.Modified;

but without any success.
I am using EF Core 3.1.15 with .Net 4.7.2

Update:
This is my DbContext class

    public partial class SIMContext : DbContext
    {
        public SIMContext()
        {
        }
        public SIMContext(DbContextOptions<SIMContext> options)
            : base(options)
        {
        }
        public virtual DbSet<Department> Departments { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings["SIMContext"].ConnectionString);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.ApplyConfiguration(new DepartmentConfiguration());
        }


    }

and this is how I inject DbContext using AutoFac

static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        public static IContainer Container;
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Container = Configure();
            Application.Run(new XtraMain(Container.Resolve<SIMContext>()));
        }
        static IContainer Configure()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<SIMContext>().AsSelf();
            builder.RegisterType<XtraMain>();
            return builder.Build();
        }
    }

And This is the main form:

     public partial class XtraMain : DevExpress.XtraBars.Ribbon.RibbonForm
    {
        private readonly SIMContext _SIMContext;
        public XtraMain(SIMContext SIMContext) 
        {
            InitializeComponent();
            _SIMContext = SIMContext;
        }
        private void bbtnDepartment_ItemClick(object sender, ItemClickEventArgs e)
        {
            Frm_Department frme = new(_SIMContext)
            {
                Name = "Frm_Department"

            };
            ViewChildForm(frme);
        }
    }

I think the problem is with the injection DbContext method.
In this way DbContext is alive for the entire lifetime of an application and if any change(update,Remove) happens outside of DbContext then I end up with stale data and do more coding to reload new data.
I think the problem will be solved if injected DbContext will disposed after each request

Windows Forms
Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,857 questions
Entity Framework Core
Entity Framework Core
A lightweight, extensible, open-source, and cross-platform version of the Entity Framework data access technology.
702 questions
SQL Server
SQL Server
A family of Microsoft relational database management and analysis systems for e-commerce, line-of-business, and data warehousing solutions.
12,895 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,387 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Daniel Zhang-MSFT 9,621 Reputation points
    2021-08-06T01:48:03.877+00:00

    Hi mbouabdallah, Entity Framework uses the Identity Map pattern. This means that once an entity with a given key is loaded in the context’s cache, it is never loaded again for as long as that context exists. Your code will never see changes to items loaded into its cache without manually reloading each entity it loads. binki has pointed out in this thread in detail. And you can refer to the following suggestions:

    1. Disable Tracking using AsNoTracking(): You can instruct Entity Framework to bypass the cache when making a query by using the AsNoTracking() method.
    2. Throw away the DbContext and create a new one.
    3. Detatch the entities: // Detatch department, removing her entity from the cache _SIMContext.Entry(department).State = EntityState.Detatched;

    Best Regards, Daniel Zhang


    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.
    0 comments No comments

  2. Karen Payne MVP 35,201 Reputation points
    2021-08-05T11:27:43.003+00:00

    Not sure if this can work for you as all my EF code is not in version 5

    _SIMContext.Entry(model).Reload();
    

    Or an extension method (written in EF Core 5, may need adjustment for EF Core 3)

    public static class DbContextHelpers
    {
        public static void Reload(this DbContext context, EntityEntry modelEntityEntry)
        {
            context.Entry(modelEntityEntry).Reload();
        }
    }
    

    Or perhaps Detach the entity, find it and do required work