2

Can someone explain to me why I am getting a design/compile time error for this.

I am trying to get the last Guid for each table, based on alast update date or created date.

var accountId = context.Account.OrderBy(x => x.LastUpdateDate).ThenBy(x=>x.LastUpdateDate).FirstOrDefaultAsync(x => x.UserAccount.ExternalId == _jwt.HomeAccountId).ExternalId;
var transactionLineId = context.TransactionLine.OrderBy(x => x.LastUpdateDate).ThenBy(x => x.LastUpdateDate).FirstOrDefaultAsync(x => x.Transaction.CreditAccount.UserAccount.ExternalId == _jwt.HomeAccountId).ExternalId;
var transactionId = context.Transaction.OrderBy(x => x.LastUpdateDate).ThenBy(x => x.LastUpdateDate).FirstOrDefaultAsync(x => x.CreditAccount.UserAccount.ExternalId == _jwt.HomeAccountId).ExternalId;
var budgetId = context.Budget.OrderBy(x => x.LastUpdateDate).ThenBy(x => x.LastUpdateDate).FirstOrDefaultAsync(x => x.UserAccount.ExternalId == _jwt.HomeAccountId).ExternalId;
var scheduleId = context.Schedule.OrderBy(x => x.LastUpdateDate).ThenBy(x => x.LastUpdateDate).FirstOrDefaultAsync(x => x.CreditAccount.UserAccount.ExternalId == _jwt.HomeAccountId).ExternalId;

And then, await each repsonse and pass to a method.

var guids = new List<Guid> { await accountId, await transactionLineId, await transactionId, await budgetId, await scheduleId };

var checkGuid = MungeTwoGuids(guids);

But I get the error:

CS1061 'Task' does not contain a definition for 'ExternalId' and no accessible extension method 'ExternalId' accepting a first argument of type 'Task' could be found (are you missing a using directive or an assembly reference?)

This happens on the first line. I thought I can call all those selects.... at once, basically... and then await all responses. Instead of call, wait, call, wait....

Is this not the right way to achieve what I am trying to do? Well, it's not, as I have an error, but am I on the wrong track with my understanding of await?

I then removed the field from the select, and try to get it like this, but ... Nope.

await accountId.Result.ExternalId,
Stefan
  • 17,448
  • 11
  • 60
  • 79
Craig
  • 18,074
  • 38
  • 147
  • 248
  • It seems, that you forgot to use `await`, try to call it like `var accountId = await context.Account.OrderBy(x => x.LastUpdateDate).ThenBy(x=>x.LastUpdateDate).FirstOrDefaultAsync(x => x.UserAccount.ExternalId == _jwt.HomeAccountId).ExternalId;` – Pavel Anikhouski Jan 04 '20 at 12:42
  • Please send the function headers(eg: public void Function(string input){ [Code] }) that I can rebuild the error – BierDav Jan 04 '20 at 12:43
  • `var accountId = (await context...FirstOrDefaultAsync(...)).ExternalId` – GSerg Jan 04 '20 at 12:43
  • @PavelAnikhouski `ExternalId` would not be awaitable. `FirstOrDefaultAsync()` is. – GSerg Jan 04 '20 at 12:44

3 Answers3

5

Your FirstOrDefaultAsync returns a Task<T>, not T itself, and thus has no ExternalId.

Normally you would have 2 options:

  • select the ExternalId upfront in a Select and await the task later, or
  • await the Task<T> first, the result will be a T, conaining your property so you can access it.

But, as @GSerg notes: the first option does not apply because executing parralell queries will result in a concurrency exception.


So, in your case it makes sense to await the FirstOrDefaultAsync directly, and use a Select, ?? or a null check to overcome the possible null ref exception.


Try to avoid the accountId.Result.ExternalId because it will make your code run synchronously and you'll loose the benefits of the asynchronous calls. See: What is the difference between await Task<T> and Task<T>.Result?

Stefan
  • 17,448
  • 11
  • 60
  • 79
2

You should change your code like this:

 var accountId = context.Account.OrderBy(x => x.LastUpdateDate).ThenBy(x=>x.LastUpdateDate).FirstOrDefaultAsync(x => x.UserAccount.ExternalId == _jwt.HomeAccountId);
 var transactionLineId = context.TransactionLine.OrderBy(x => x.LastUpdateDate).ThenBy(x => x.LastUpdateDate).FirstOrDefaultAsync(x => x.Transaction.CreditAccount.UserAccount.ExternalId == _jwt.HomeAccountId);
 var transactionId = context.Transaction.OrderBy(x => x.LastUpdateDate).ThenBy(x => x.LastUpdateDate).FirstOrDefaultAsync(x => x.CreditAccount.UserAccount.ExternalId == _jwt.HomeAccountId);
 var budgetId = context.Budget.OrderBy(x => x.LastUpdateDate).ThenBy(x => x.LastUpdateDate).FirstOrDefaultAsync(x => x.UserAccount.ExternalId == _jwt.HomeAccountId);
 var scheduleId = context.Schedule.OrderBy(x => x.LastUpdateDate).ThenBy(x => x.LastUpdateDate).FirstOrDefaultAsync(x => x.CreditAccount.UserAccount.ExternalId == _jwt.HomeAccountId);


var guids = new List<Guid> { 
          (await accountId).ExternalId,
          (await transactionLineId).ExternalId,
          (await transactionId).ExternalId,
          (await budgetId).Externalid,
          (await scheduleId).EternalId };

var checkGuid = MungeTwoGuids(guids);

In that way, you are first awaiting the Tasks you started and then use the 'ExternalId' property of the result each tasks returns.

Important edit: The changes above will solve the original problem, but as was pointed out in the comment by GSerg below, you will get an exception, since EF does not allow simultaneous asynchroneous operations on the same context.

You could solve this by:

a) immediately await each task

b) if you really want parallel execution: create a separate context for each task

Johan Donne
  • 3,104
  • 14
  • 21
0

Please do like below.

var accountId = (await context.Account.OrderBy(x => x.LastUpdateDate).ThenBy(x=>x.LastUpdateDate).FirstOrDefaultAsync(x => x.UserAccount.ExternalId == _jwt.HomeAccountId)).ExternalId;
var transactionLineId = (await context.TransactionLine.OrderBy(x => x.LastUpdateDate).ThenBy(x => x.LastUpdateDate).FirstOrDefaultAsync(x => x.Transaction.CreditAccount.UserAccount.ExternalId == _jwt.HomeAccountId)).ExternalId;
var transactionId = (await context.Transaction.OrderBy(x => x.LastUpdateDate).ThenBy(x => x.LastUpdateDate).FirstOrDefaultAsync(x => x.CreditAccount.UserAccount.ExternalId == _jwt.HomeAccountId)).ExternalId;
var budgetId = (await context.Budget.OrderBy(x => x.LastUpdateDate).ThenBy(x => x.LastUpdateDate).FirstOrDefaultAsync(x => x.UserAccount.ExternalId == _jwt.HomeAccountId)).ExternalId;
var scheduleId = (await context.Schedule.OrderBy(x => x.LastUpdateDate).ThenBy(x => x.LastUpdateDate).FirstOrDefaultAsync(x => x.CreditAccount.UserAccount.ExternalId == _jwt.HomeAccountId)).ExternalId

Then

var guids = new List<Guid> {accountId, transactionLineId, transactionId, budgetId, scheduleId};
var checkGuid = MungeTwoGuids(guids);