11

This is my Table:Statistics

Id,Depth,RefreshCounter

Sample Records:

Id    Depth      RefreshCounter
 1     1           1
 2     1           0
 3     1           0
 4     1           0

Now what i need to do is whenever i am refreshing the page i need to increment this refreshcounter value by 1 in Database table with Depth 1.

I am calling this method like this on load of my view page:

@Html.Action("IncrementRefreshcounter", "Statistics", new { id = 1})  //for eg:1,2,3,4

Here is my code which does this:

    [ChildActionOnly]
    public ActionResult IncrementRefreshcounter(int id)
       {
         using ( var context = new MyDBContext())
         {
//at each page refresh i would be passing different id to my controller from view.for eg 1,2,3,4
         var data=context.Statistics.where(x=>x.Depth==1 && r.Id==id).FirstorDefualt();
             context.RefreshCounter++;//Increment here RefreshCounter.
             context.SaveChangesAsync();
             return PartialView("xxx")
            }
        }

I am calling this method when my View Loads.Problem is when i run my Application first time and calling this method it successfully updated RefreshCounter by 1 but after that whenever i refresh my page and calling this method it never updated RefreshCounter for any records with Depth=1.

In my sample Records you can see that Id 1 with Depth 1 have refresh counter with value 1 because it was the first time when i have run my application and it has successfully updated that value but after that it is never updating any value for eg:Id 2 Depth 1

It is incrementing only 1 time RefreshCounter but after that it never increments that variable.

Can anybody tell me what the problem is SaveChangesAsync ??

I Love Stackoverflow
  • 6,738
  • 20
  • 97
  • 216
  • Do you want to update other records with `Depth==1` or just the first record? – Mehrdad Kamelzadeh May 22 '15 at 05:21
  • @MehrdadKamelzadeh:other records too not just depth==1 and id==1.others records too because at each refresh i would be passing different id to my controller – I Love Stackoverflow May 22 '15 at 05:23
  • So why you have written `where(x=>x.Depth==1).FirstorDefualt()` ?? it returns only the first record found by the criteria. I mean it finds all the records which their `Depth==1` and then it returns just the first one! – Mehrdad Kamelzadeh May 22 '15 at 05:24

2 Answers2

15

You have to await the save otherwise the method will continue and your context would go out of scope before saving changes. You have to make the method asynchronous, too.

public **async** Task<ActionResult> IncrementRefreshcounter(int id)
       {
         using ( var context = new MyDBContext())
         {
//at each page refresh i would be passing different id to my controller from view.for eg 1,2,3,4
         var data=context.Statistics.where(x=>x.Depth==1 && r.Id==id).FirstorDefualt();
             context.RefreshCounter++;//Increment here RefreshCounter.
             await context.SaveChangesAsync();
            }
        }
Eddie Paz
  • 2,219
  • 16
  • 11
  • like how as because my method is actionresult.can you please post any sample? – I Love Stackoverflow May 22 '15 at 05:31
  • See my updated answer. You need to return the action result as you normally would such a view or redirect. – Eddie Paz May 22 '15 at 05:33
  • Please see my updated question and i have dont with what you have written but getting thsi error:HttpServerUtility.Execute blocked while waiting for an asynchronous operation to complete – I Love Stackoverflow May 22 '15 at 05:43
  • 1
    Before getting into the the async world (all involved methods must be async up the chain), so revert your code to synchronous: remove async Task<> from the method, and await, call the synchronous context.SaveChanges method instead. I mentioned in my previous comment a possible error in your code where "data" is not being used. Once this issue is solved, you can try async calls. – Eddie Paz May 22 '15 at 05:52
  • you are right sir.context.savechanges is working correctly but i dont want to use conext.savechanges.i want to go with SaveChangesAsync only.So any solution for this sir? – I Love Stackoverflow May 22 '15 at 05:56
  • 1
    Unfortunately, you cannot call an async method from @Html.Action() - it's not supported: https://aspnetwebstack.codeplex.com/workitem/601 - I would consider creating a helper class to increment the counter, and calling it from the action that loads the view from which you're using @Html.Action(). – Eddie Paz May 22 '15 at 06:06
  • thank you so much sir for your kind help.sir any other possible solution like without using html.action and calling my controller method and then using await and async – I Love Stackoverflow May 22 '15 at 06:20
  • Sir can you please tell me the difference between two save changes and SaveChangesAsync and when to use one over other?? – I Love Stackoverflow May 23 '15 at 03:51
9

Try this:

   public async Task<ActionResult> IncrementRefreshcounter(int id)
   {
     using ( var context = new MyDBContext())
     {
//at each page refresh i would be passing different id to my controller from view.for eg 1,2,3,4
     var data=context.Statistics.where(x=>x.Depth==1 && r.Id==id).FirstorDefualt();
         context.RefreshCounter++;//Increment here RefreshCounter.
         await context.SaveChangesAsync();
        }
    }

SaveChanges will execute on the current thread and block the thread while waiting for the query to complete, preventing the thread from doing other work, even though the thread is just sitting there waiting for IO.

SaveChangesAsync will kick off the IO command and then free up the request thread to do other work while the IO is in progress. Once the IO completes, the rest of the method is executed on the captured synchronization context.

So for a web server using asyncrhonous APIs for IO bound work enables you to serve more requests with fewer threads and thus makes your application more scalable and it will use much less memory as well as each thread has 1MB of stack space by default.

Synchronous work is like the SaveChanges method. The method call does not return until the changes are saved.

Asynchronous work is like SaveChangesAsync, the method call initiates the operation and returns a Task so you can keep track of it. The changes are then saved in the background some time later and in the mean time you can use the returned Task to keep track of the operation.

NeddySpaghetti
  • 13,187
  • 5
  • 32
  • 61