我有一种方法可以让用户登录并尝试在用户viewModel
与user
对象不同时更新用户。我看到的行为令人困惑。
每次执行该方法时,如果user
之前未登录,则该行将await _userManager.UpdateAsync(user);
失败并出现异常:("There is no user with id: 99"
或任何id
值)。但是,如果先前user
已登录,则该行有效。
例如,
- 用户启动应用程序(当前未登录)并单击按钮发布
viewModel
到服务器。 - 该应用程序登录
user
, - 如果 与
viewModel
现有user
的数据不同,服务器会尝试更新它。 - 此更新将失败
"There is no user with id: 99"
- 用户再次单击按钮并将相同的数据发布到服务器。(这次
user
是从之前失败的帖子登录的) viewModel
仍然与现有数据不同(记住,上次更新失败)await _userManager.UpdateAsync(user);
工作并且记录被更新。
以下是方法:
[UnitOfWork]
public async Task<AjaxResponse> Post(MyViewModel viewModel)
{
try
{
var loginResult = await _userManager.LoginAsync(viewModel.UserName, viewModel.Password, viewModel.TenancyName);
User user;
if (loginResult.Result == AbpLoginResultType.Success)
{
await SignInAsync(loginResult.User, loginResult.Identity);
user = loginResult.User;
if (user.AccessToken != viewModel.AccessToken)
{
user.AccessToken = viewModel.AccessToken;
// why does this fail the first time?
await _userManager.UpdateAsync(user);
}
}
else
{
/* do some other UnitOfWork stuff below */
}
return new AjaxResponse(new MyResult
{
Name = user.Name + " " + user.Surname,
UserName = user.UserName,
EmailAddress = user.EmailAddress,
IsActive = user.IsActive,
Success = true,
UserId = user.UserId,
});
}
catch (Exception ex)
{
throw new HttpException((int)HttpStatusCode.InternalServerError, ex.Message);
}
}
我可以确认 ID 为 99 的用户确实存在于数据库中。
为了记录,以下是内容ex.StackTrace
at Abp.Authorization.Users.AbpUserManager`3.<GetUserByIdAsync>d__5b.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Abp.Authorization.Users.AbpUserManager`3.<UpdateAsync>d__64.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at MyProject.Web.Controllers.Api.AccountApiController.<Post>d__16.MoveNext() in C:\dev\MyProject\MyProject.Web\Controllers\Api\AccountApiController.cs:line 146
我认为一个线索可能是在更新之前执行的以下查询(被 SQL Server Profiler 拦截):
exec sp_executesql N'SELECT TOP (1)
[Extent1].[Id] AS [Id],
[Extent1].[AccessToken] AS [AccessToken],
[Extent1].[UserId] AS [UserId],
[Extent1].[EmailAddress] AS [EmailAddress],
[Extent1].[TenantId] AS [TenantId],
[Extent1].[IsDeleted] AS [IsDeleted],
-- irrelevant stuff removed
FROM [dbo].[AbpUsers] AS [Extent1]
WHERE
((([Extent1].[TenantId] IS NULL) AND (@DynamicFilterParam_1 IS NULL))
OR (([Extent1].[TenantId] IS NOT NULL) AND ([Extent1].[TenantId] = @DynamicFilterParam_1))
OR (@DynamicFilterParam_2 IS NOT NULL)) AND (([Extent1].[IsDeleted] = @DynamicFilterParam_3)
OR (@DynamicFilterParam_4 IS NOT NULL)) AND ([Extent1].[EmailAddress] = @p__linq__0)',
N'@DynamicFilterParam_1 int,@DynamicFilterParam_2 bit,@DynamicFilterParam_3 bit,@DynamicFilterParam_4 bit,@p__linq__0 nvarchar(4000)'
,@DynamicFilterParam_1=NULL,@DynamicFilterParam_2=NULL,@DynamicFilterParam_3=0,@DynamicFilterParam_4=NULL,@p__linq__0=N'myemail@mail.com'
在这里,我们可以看到@DynamicFilterParam_1=NULL
。该变量@DynamicFilterParam_1
对应于 的值[Extent1].[TenantId]
。如果我手动分配值2
(这是与数据库中的记录关联的值)而不是NULL
重新运行查询,它会按我的预期返回记录。
当我第二次执行该方法时,我可以看到 TenantId 被正确分配了值 2。
为什么第一次给 TenantId 对应的值赋值为 NULL?为什么该UpdateAsync
方法每次都失败?我该怎么做才能让它发挥作用?
为了响应下面的请求,在asp.net 样板 github中提供了 UpdateAsync 的定义