I have a WPF application that works with a database. The number of records in the database is quite large and constantly growing. The project uses ORM (EF 6). There is a class that works directly with the database context:

public class Store : IStore {...} 

In the class interface, a number of methods are defined, the code in which refers directly to the database through the EF context, respectively, the method takes quite a long time to execute, which can cause a simple user interface if I understand correctly. Consequently, it is necessary to make operations of receiving data from the database into separate streams. So, let's say, the Store a method defined:

 public ICollection<Product> GetAllProducts() {...} 

If I understand correctly, I need to add its asynchronous implementation:

 public async Task<ICollection<Product>> GetAllProductsAsync() { return await Task<ICollection<Product>>.Factory.StartNew(GetAllProducts) } 

How to use this method correctly in the application itself in the ViewModel . Let us say that while the data is being loaded, the StatusBar displays the data loading progress and the DataGrid displays the result as soon as the data is loaded?

    1 answer 1

    OK, let's start with Task.Factory.StartNew . This is only necessary if your database request does not support asynchronous itself, and requires the allocation of a separate thread (by the way, it's better to just write Task.Run ).

    For a fresh Entity Framework, this is not the case; asynchronous functions are supported correctly, out of the box: Entity Framework tutorial: async query and save .

    With asynchrony at the database level, you do not need to create separate threads.


    About progress, with this worse. EF does not support information about the progress of the operation, so you can simply deduce the state of “reading”, and read until you finish.

    In the case when / if progress support is implemented, you can use the IProgress<T> interface.


    Thus, the code in the VM will look like this:

     IsLoading = true; var localData = await model.LoadDataAsync(); IsLoading = false; Data = localData; 

    Most likely, you do not want to lay out model classes for View, so you need a wrapper that creates VM objects for your entity:

     // в модели IQueryable<TEntity> GetData(); 
     // в VM IsLoading = true; var localData = new List<EntityVM>(); await model.GetData().ForEachAsync(entity => localData.Add(new EntityVM(entity)); IsLoading = false; Data = localData; 

    Well, as @Pavel Mayorov rightly notes, you may want to catch exceptions, so you'll need to try:

     IsLoading = true; var localData = new List<EntityVM>(); try { await model.GetData().ForEachAsync(entity => localData.Add(new EntityVM(entity)); Data = new ObservableCollection<EntityVM>(localData); } catch { IsFailed = true; throw; } finally { IsLoading = false; } 

    Or, if you want the data to not appear all together, but as it loads, it will probably just fit

      await model.GetData().ForEachAsync(entity => Data.Add(new EntityVM(entity)); 

    (but here I am not sure, because I have never tried).

    • “With regard to progress, this is worse. EF does not support information on the progress of the operation, so you can simply deduce the state of“ reading ”and read until you finish it.” - and how will it look in VIewModel? - klutch1991
    • @ klutch1991: Added the code. - VladD
    • @ klutch1991: Added more. - VladD
    • @VladD And what will the GetData method signature look like? Is this my asynchronous method? - klutch1991
    • one
      @ klutch1991 if the operation requires a lot of CPU time or uses a synchronous API - then through Task.Run . But first, it is better to look for an asynchronous API for the operation. - Pavel Mayorov