question

mbouabdallah avatar image
0 Votes"
mbouabdallah asked DanielZhang-MSFT commented

EF Core 3.1 get data that updated out of the DbContext

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



sql-server-generaldotnet-csharpwindows-formsdotnet-entity-framework-core
· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.


Maybe you should dispose the _SIMContext and use a new one?


0 Votes 0 ·

I am afraid not possible I am using Dependency injection

0 Votes 0 ·

Some articles recommend something like this:

 ((IObjectContextAdapter)_SIMContext).Refresh(RefreshMode.StoreWins, _SIMContext.Departments);


0 Votes 0 ·

Hi @mbouabdallah,
May I know whether your issue has been solved or not? If not, please share it in here. We can work together to figure it out.
Best Regards,
Daniel Zhang

0 Votes 0 ·
karenpayneoregon avatar image
0 Votes"
karenpayneoregon answered mbouabdallah commented

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

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

 _SIMContext.Entry(model).Reload();

unfortunately, does not work
I am going with this solution from Richard Deeming
it is solving the modifying records.
The removed records do not affect //on progress

 private async Task LoadDataAsync(bool refresh = false)
 {
     if (refresh)
     {
         var departments = await _SIMContext.Departments.ToListAsync();
         foreach (var department in departments)
         {
             await _SIMContext.Entry(department).ReloadAsync();
         }
     }
     else
     {
         await _SIMContext.Departments.LoadAsync();
     }
        
     dataBindingSource.DataSource = _SIMContext.Departments.Local.ToBindingList();
 }



1 Vote 1 ·
DanielZhang-MSFT avatar image
1 Vote"
DanielZhang-MSFT answered

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.


5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.