New Posts New Posts RSS Feed: Retrieving and Updating Next Invoice #
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Retrieving and Updating Next Invoice #

 Post Reply Post Reply Page  12>
Author
BillG View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 05-Dec-2007
Location: Monroe, MI
Posts: 233
Post Options Post Options   Quote BillG Quote  Post ReplyReply Direct Link To This Post Topic: Retrieving and Updating Next Invoice #
    Posted: 21-Nov-2010 at 4:41pm
I have a table that has a field called NextInvoiceNo. I need to read in the table, grab the NextInvoiceNo update it by 1 and write it back to the table immediately so that the next user can grab the next number. Unfortunately the following does not work because of the Asynchronou call. How can I fix this code to make it work properly?

public JobHistory CreateJobHistory()

{

JobHistory job = new JobHistory();

int refNo = GetNextRefNo();

job = JobHistory.Create(Mgr, CurrentMember.SocSecNo, refNo);

return job;

}

public int GetNextRefNo()

{

int nextRefNo = 0;

var query = from LocalInfo in Mgr.LocalInfos

select LocalInfo;

Mgr.ExecuteQueryAsync<LocalInfo>((IEntityQuery<LocalInfo>)query,

(op) =>

{

var results = op.Results;

LocalInfo local = results.FirstOrDefault<LocalInfo>();

nextRefNo = local.NextJobHistRef;

local.NextJobHistRef = nextRefNo + 1;

List<Entity> changedEntities = new List<Entity>();

changedEntities.Add(local);

Mgr.SaveChangesAsync(changedEntities);

});

return nextRefNo;

Back to Top
BillG View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 05-Dec-2007
Location: Monroe, MI
Posts: 233
Post Options Post Options   Quote BillG Quote  Post ReplyReply Direct Link To This Post Posted: 22-Nov-2010 at 11:10am
would the solution to this problem be to use Coroutines?
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 22-Nov-2010 at 5:47pm
Hi Bill;

You're maybe right. I think this is how you would implement something similar to what you want to do using Coroutine.

//Coroutine caller

private JobHistory GetNewJobHistory() {

 var coop = Coroutine.Start(CreateJobHistory);
 coop.Completed += (sender, args) => {
   
    if (args.CompletedSuccessfully) {
       return coop.Result as JobHistory;
    } else {
         //Error handler here
    }
 }
}

//Coroutine Iterator
private IEnumerable<INotifyCompleted> CreateJobHistory() {

  //Query for all LocalInfo and suspend return calls
  var localInfoOp = Mgr.LocalInfos.ExecuteAsync();
  yield return localInfoOp;

  //Get first LocalInfo.NextJobHistRef and increment by 1
  List<LocalInfo> localInfos = localInfoOp.Results;
  int nextRefNo = localInfos[0].NextJobHistRef;
  localInfos[0].NextJobHistRef = nextRefNo + 1;

  //Create a new JobHistory
  JobHistory job = JobHistory.Create(Mgr, CurrentMember.SocSecNo, nextRefNo);

  //Create changedEntities and add first LocalInfo to it.
  List<Entity> changedEntities = new List<Entity>();
  changedEntities.Add(localInfos[0]);

  //Save Async
  Mgr.SaveChangesAsync(changedEntities);

  //Finally return the newly created JobHistory
  yield return Coroutine.Return(job);
}
Back to Top
BillG View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 05-Dec-2007
Location: Monroe, MI
Posts: 233
Post Options Post Options   Quote BillG Quote  Post ReplyReply Direct Link To This Post Posted: 22-Nov-2010 at 7:46pm
I put in the new code but I can't compile it because of the following errors:
 

private JobHistory GetNewJobHistory() {

var coop = Coroutine.Start(CreateJobHistory);

coop.Completed += (sender, args) =>{

if (args.CompletedSuccessfully){

return coop.Result as JobHistory;

Error 1 Cannot convert lambda expression to delegate type 'System.EventHandler<IdeaBlade.EntityModel.CoroutineCompletedEventArgs>' because some of the return types in the block are not implicitly convertible to the delegate return type C:\Software Development\VS2010\LaborWare2011\LaborWare2011\ViewModels\MemberViewModel.cs 566 21 LaborWare2011
Error 2 Since 'System.EventHandler<IdeaBlade.EntityModel.CoroutineCompletedEventArgs>' returns void, a return keyword must not be followed by an object expression C:\Software Development\VS2010\LaborWare2011\LaborWare2011\ViewModels\MemberViewModel.cs 566 21 LaborWare2011
}

else

{

//Error handler here

}

};

}

Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 23-Nov-2010 at 12:39pm
Oops, my apologies Bill. Here's a new code snippet using the NorthwindIB database. It has a similar concept to what you're trying to do.

//Coroutine caller
    private void BatchingMultipleAsynchronousTasksWithCoroutines() {
      var coop = Coroutine.Start(CreateAnOrderUsingAnotherOrder);
      coop.Completed += (sender, args) => {
        if (args.CompletedSuccessfully) {
          Order newOrder = coop.Result as Order;
          Output += newOrder.ShipName + Environment.NewLine;
        } else {
          //Error handler here
          Output += "New Order creation failed: " + Environment.NewLine;
        }
      };
    }

    //Coroutine Iterator
    private IEnumerable<INotifyCompleted> CreateAnOrderUsingAnotherOrder() {
      //Query for all Orders and suspend return calls
      var orderOp = _mainMgr.Orders.ExecuteAsync();
      yield return orderOp;

      //Get first Order property, modify it and create a new order using this modified property
      List<Order> orders = new List<Order>(orderOp.Results);
      string newShipName = orders[0].ShipName + "xxx";
      orders[0].ShipName = "Vins et alcools Chevalier" + DateTime.Now.Millisecond.ToString();

      //Create a new Order
      Order newOrder = new Order();
      newOrder.ShipName = newShipName;

      //Create changedEntities and add first Order to it
      List<Entity> changedEntities = new List<Entity>();
      changedEntities.Add(orders[0]);

      //Save async
      var saveOp = _mainMgr.SaveChangesAsync(changedEntities);
      saveOp.Completed += (sender, args) => {
        if (args.CompletedSuccessfully) {
          var savedOrder = args.Entities[0] as Order;
          Output += "Save is successful: " + savedOrder.ShipName + Environment.NewLine;
        } else {
          Output += "Save failed" + Environment.NewLine;
        }
      };

      //Finally return the newly created Order
      yield return Coroutine.Return(newOrder);
    }
Back to Top
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post Posted: 23-Nov-2010 at 3:06pm
I haven't really looked at the other solutions, but couldn't you do something like this:

Create Invoice object
Pass new invoice object to a function that makes the async retrieval code, updates the object, and then calls the update code?

This way you create and return your invoice object immediately, and the invoice Id is assigned when the async call returns
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 23-Nov-2010 at 3:21pm
smi-mark,

Yes, that sounds like that would work as well.
Back to Top
BillG View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 05-Dec-2007
Location: Monroe, MI
Posts: 233
Post Options Post Options   Quote BillG Quote  Post ReplyReply Direct Link To This Post Posted: 23-Nov-2010 at 4:03pm

Where did you get this code snippet? Is it available with the download. If there a place to find all code snippets?

Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 23-Nov-2010 at 4:10pm
BillG,

I actually just wrote and tested that code snippet.

In case you haven't heard, we are creating a new section in our Wiki called the Cookbook. The Cookbook contains short code snippet to teach users how to use DF. Please see below for more info.

Back to Top
BillG View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 05-Dec-2007
Location: Monroe, MI
Posts: 233
Post Options Post Options   Quote BillG Quote  Post ReplyReply Direct Link To This Post Posted: 23-Nov-2010 at 4:33pm
I fixed up the new code that you gave me and it compiles fine but the problem is that when it executes the executeAsynce method and I step through the code it fails to fetch a row from the LocalInfos table before it hits the first yield return and the it exits the Coroutine iterator method and returns back to the calling coroutine method.
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 23-Nov-2010 at 4:44pm
Could you paste your code here and highlight where it fails?
Back to Top
BillG View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 05-Dec-2007
Location: Monroe, MI
Posts: 233
Post Options Post Options   Quote BillG Quote  Post ReplyReply Direct Link To This Post Posted: 23-Nov-2010 at 4:49pm

private void CreateNewJobHistoryCoRoutine()

{

var coop = Coroutine.Start(CreateJobHistory);

coop.Completed += (sender, args) =>

{

if (args.CompletedSuccessfully)

{

newJob = coop.Result as JobHistory;

// Order newOrder = coop.Result as Order;

//// Output += newOrder.ShipName + Environment.NewLine;

}

else

{

//Error handler here

// Output += "New Order creation failed: " + Environment.NewLine;

}

};

}

 

//Coroutine Iterator

private IEnumerable<INotifyCompleted> CreateJobHistory()

{

var localInfoOp = Mgr.LocalInfos.ExecuteAsync() //fails to yield any rows, table has 1 row in it. 

yield return localInfoOp;

 

//Get first LocalInfo.NextJobHistRef and increment by 1

LocalInfo localInfos = localInfoOp.Results.First<LocalInfo>();

int nextRefNo = localInfos.NextJobHistRef;

localInfos.NextJobHistRef = nextRefNo + 1;

 

//Create a new JobHistory

JobHistory newJob = JobHistory.Create(Mgr, CurrentMember.SocSecNo, nextRefNo);

 

//Create changedEntities and add first LocalInfo to it.

List<Entity> changedEntities = new List<Entity>();

changedEntities.Add(localInfos);

 

//Save Async

var saveOp = Mgr.SaveChangesAsync(changedEntities);

saveOp.Completed += (sender, args) =>

{

if (args.CompletedSuccessfully)

{

// var savedOrder = args.Entities[0] as Order;

// Output += "Save is successful: " + savedOrder.ShipName + Environment.NewLine;

}

else

{

//Output += "Save failed" + Environment.NewLine;

}

};

yield return Coroutine.Return(newJob);

}

Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 23-Nov-2010 at 5:07pm
Hmm, that's strange. This is a straightforward query. Could you try another query with a different entity?
Back to Top
BillG View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 05-Dec-2007
Location: Monroe, MI
Posts: 233
Post Options Post Options   Quote BillG Quote  Post ReplyReply Direct Link To This Post Posted: 23-Nov-2010 at 5:19pm

same thing with another table that at least 50 rows in it. It's almost like it hasn't had time to retrieve the rows by the time it reaches the yield return statement. Does it make a difference that I am using the development server and am not using the BOS in my development machine?

Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 23-Nov-2010 at 6:08pm
Have you tried letting it run and wait until it creates the new JobHistory?

Reading your post again, it sounds like what you're describing is a normal operation.

"when it executes the executeAsynce method and I step through the code it fails to fetch a row from the LocalInfos table before it hits the first yield return and the it exits the Coroutine iterator method and returns back to the calling coroutine method."

when the first yield return is hit, execution is being stopped temporarily in the CreateJobHistory routine and will only resume when the previous ExecuteAsync is completed. You saw that it exits the Coroutine iterator method back to the calling coroutine method. This is because the coroutine itself is an async operation. So the whole operation isn't done yet. At this point, the line Manager.LocalInfos.ExecuteAsync() is still getting the LocalInfos and hasn't come back yet.

Try putting your breakpoint at this line and see if it reaches it.

int nextRefNo = localInfos.NextJobHistRef;


Back to Top
BillG View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 05-Dec-2007
Location: Monroe, MI
Posts: 233
Post Options Post Options   Quote BillG Quote  Post ReplyReply Direct Link To This Post Posted: 23-Nov-2010 at 6:34pm
It never reaches the breakpoint.
 
Here is a silly thought. I am developing on a machine running Windows 7 64 bit and running the app in OOB. I know that 64 bit IE does not support Silverlight could there be problems also with OOB and 64 bit?
 
Back to Top
 Post Reply Post Reply Page  12>

Forum Jump Forum Permissions View Drop Down