短时间内发送多个请求时 DbContext 不更新
DbContext not update when multiple requests are sent in a short time
目前,我正在使用 angularjs 和网络 api 为我的公司开发网络系统 2.
在系统中,我们允许用户使用api将帐户添加到数据库中。
这是它的流程:
调用 api/user 将用户添加到数据库中。
添加特定信息的用户信息:
- Id(由数据库自动生成)
- RepresentationCode(通过连接 USER_REPRESENTATION_{MaxUserIndex}
举个例子,假设数据库是空的。
同时调用api/user20次
这些是创建到数据库中的记录。
1 USER_REPRESENTATION_1 2018-03-17 01:51:02.140 NULL
2 USER_REPRESENTATION_1 2018-03-17 01:51:02.140 NULL
3 USER_REPRESENTATION_3 2018-03-17 01:51:02.417 NULL
4 USER_REPRESENTATION_3 2018-03-17 01:51:02.420 NULL
5 USER_REPRESENTATION_4 2018-03-17 01:51:02.427 NULL
6 USER_REPRESENTATION_6 2018-03-17 01:51:02.437 NULL
7 USER_REPRESENTATION_6 2018-03-17 01:51:02.437 NULL
8 USER_REPRESENTATION_8 2018-03-17 01:51:02.443 NULL
用户表示代码与某些记录重复。
- 我的期望是:
1 USER_REPRESENTATION_1 2018-03-17 01:51:02.140 NULL
2 USER_REPRESENTATION_2 2018-03-17 01:51:02.140 NULL
3 USER_REPRESENTATION_3 2018-03-17 01:51:02.417 NULL
4 USER_REPRESENTATION_4 2018-03-17 01:51:02.420 NULL
5 USER_REPRESENTATION_5 2018-03-17 01:51:02.427 NULL
6 USER_REPRESENTATION_6 2018-03-17 01:51:02.437 NULL
7 USER_REPRESENTATION_7 2018-03-17 01:51:02.437 NULL
8 USER_REPRESENTATION_8 2018-03-17 01:51:02.443 NULL
这是注册DI的代码:
// Initiate container builder to register dependency injection.
var containerBuilder = new ContainerBuilder();
#region Controllers & hubs
// Controllers & hubs
containerBuilder.RegisterApiControllers(typeof(Startup).Assembly);
containerBuilder.RegisterWebApiFilterProvider(httpConfiguration);
#endregion
#region Unit of work & Database context
// Database context initialization.
containerBuilder.RegisterType<RelationalDbContext>().As<DbContext>().InstancePerLifetimeScope();
// Unit of work registration.
containerBuilder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
#endregion
#region IoC build
// Container build.
containerBuilder.RegisterWebApiFilterProvider(httpConfiguration);
var container = containerBuilder.Build();
// Attach DI resolver.
httpConfiguration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
这是我的ApiUserController
public IHttpActionResult AddUser()
{
// Get users list.
var users = _unitOfWork.Users.Get();
// Get max user id.
var iMaxUserIndex = users.Max(x => (int?)x.Id) ?? 0;
iMaxUserIndex++;
var user = new User();
user.RepresentationCode = $"USER_REPRESENTATION_{iMaxUserIndex}";
user.CreatedTime = DateTime.Now;
_unitOfWork.Users.Add(user);
_unitOfWork.Commit();
return Ok();
}
搜索解决方案后,这是我使用的临时解决方案。创建记录时,我使用触发器更新用户表示代码。
下面是我的触发器:
IF EXISTS (SELECT * FROM sys.objects WHERE [type] = 'TR' AND [name] = 'addUserRepresentationCode')
DROP TRIGGER addUserRepresentationCode
GO
CREATE TRIGGER addUserRepresentationCode ON [dbo].[Users]
FOR INSERT, UPDATE
AS
BEGIN
DECLARE @userId INT;
SELECT @userId = Id FROM INSERTED
UPDATE [dbo].[Users]
SET RepresentationCode = 'USER_REPRESENTATION_' + CAST(@userId as varchar(10))
WHERE Id = @userId
END
我的触发器工作正常,符合我的要求。
但我还有一个问题:
- 我可以在没有触发器帮助的情况下使用纯 Entity Framework 添加用户表示代码吗?
谢谢,
您的代码不起作用,因为多个连续请求最终可能会得到相同的 iMaxUserIndex
值。
例如,请求 A 命中您的控制器并执行此行:
var iMaxUserIndex = users.Max(x => (int?)x.Id) ?? 0;
然后,在请求 A 的线程可以添加实体并保存数据库之前,请求 B 命中您的控制器并执行上面的同一行。结果是两个请求具有相同的 iMaxUserIndex
值。
设置 RepresentationCode
变量最简单的选项是将其设为数据库中的计算列,或者如果数据库中不需要该列,只需将其设为只读 属性 在你的域模型中。
public string RepresentationCode { get; } = $"USER_REPRESENTATION_{Id}";
目前,我正在使用 angularjs 和网络 api 为我的公司开发网络系统 2.
在系统中,我们允许用户使用api将帐户添加到数据库中。 这是它的流程:
调用 api/user 将用户添加到数据库中。
添加特定信息的用户信息:
- Id(由数据库自动生成)
- RepresentationCode(通过连接 USER_REPRESENTATION_{MaxUserIndex}
举个例子,假设数据库是空的。
同时调用api/user20次
这些是创建到数据库中的记录。
1 USER_REPRESENTATION_1 2018-03-17 01:51:02.140 NULL
2 USER_REPRESENTATION_1 2018-03-17 01:51:02.140 NULL
3 USER_REPRESENTATION_3 2018-03-17 01:51:02.417 NULL
4 USER_REPRESENTATION_3 2018-03-17 01:51:02.420 NULL
5 USER_REPRESENTATION_4 2018-03-17 01:51:02.427 NULL
6 USER_REPRESENTATION_6 2018-03-17 01:51:02.437 NULL
7 USER_REPRESENTATION_6 2018-03-17 01:51:02.437 NULL
8 USER_REPRESENTATION_8 2018-03-17 01:51:02.443 NULL
用户表示代码与某些记录重复。
- 我的期望是:
1 USER_REPRESENTATION_1 2018-03-17 01:51:02.140 NULL
2 USER_REPRESENTATION_2 2018-03-17 01:51:02.140 NULL
3 USER_REPRESENTATION_3 2018-03-17 01:51:02.417 NULL
4 USER_REPRESENTATION_4 2018-03-17 01:51:02.420 NULL
5 USER_REPRESENTATION_5 2018-03-17 01:51:02.427 NULL
6 USER_REPRESENTATION_6 2018-03-17 01:51:02.437 NULL
7 USER_REPRESENTATION_7 2018-03-17 01:51:02.437 NULL
8 USER_REPRESENTATION_8 2018-03-17 01:51:02.443 NULL
这是注册DI的代码:
// Initiate container builder to register dependency injection.
var containerBuilder = new ContainerBuilder();
#region Controllers & hubs
// Controllers & hubs
containerBuilder.RegisterApiControllers(typeof(Startup).Assembly);
containerBuilder.RegisterWebApiFilterProvider(httpConfiguration);
#endregion
#region Unit of work & Database context
// Database context initialization.
containerBuilder.RegisterType<RelationalDbContext>().As<DbContext>().InstancePerLifetimeScope();
// Unit of work registration.
containerBuilder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
#endregion
#region IoC build
// Container build.
containerBuilder.RegisterWebApiFilterProvider(httpConfiguration);
var container = containerBuilder.Build();
// Attach DI resolver.
httpConfiguration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
这是我的ApiUserController
public IHttpActionResult AddUser()
{
// Get users list.
var users = _unitOfWork.Users.Get();
// Get max user id.
var iMaxUserIndex = users.Max(x => (int?)x.Id) ?? 0;
iMaxUserIndex++;
var user = new User();
user.RepresentationCode = $"USER_REPRESENTATION_{iMaxUserIndex}";
user.CreatedTime = DateTime.Now;
_unitOfWork.Users.Add(user);
_unitOfWork.Commit();
return Ok();
}
搜索解决方案后,这是我使用的临时解决方案。创建记录时,我使用触发器更新用户表示代码。
下面是我的触发器:
IF EXISTS (SELECT * FROM sys.objects WHERE [type] = 'TR' AND [name] = 'addUserRepresentationCode')
DROP TRIGGER addUserRepresentationCode
GO
CREATE TRIGGER addUserRepresentationCode ON [dbo].[Users]
FOR INSERT, UPDATE
AS
BEGIN
DECLARE @userId INT;
SELECT @userId = Id FROM INSERTED
UPDATE [dbo].[Users]
SET RepresentationCode = 'USER_REPRESENTATION_' + CAST(@userId as varchar(10))
WHERE Id = @userId
END
我的触发器工作正常,符合我的要求。
但我还有一个问题:
- 我可以在没有触发器帮助的情况下使用纯 Entity Framework 添加用户表示代码吗?
谢谢,
您的代码不起作用,因为多个连续请求最终可能会得到相同的 iMaxUserIndex
值。
例如,请求 A 命中您的控制器并执行此行:
var iMaxUserIndex = users.Max(x => (int?)x.Id) ?? 0;
然后,在请求 A 的线程可以添加实体并保存数据库之前,请求 B 命中您的控制器并执行上面的同一行。结果是两个请求具有相同的 iMaxUserIndex
值。
设置 RepresentationCode
变量最简单的选项是将其设为数据库中的计算列,或者如果数据库中不需要该列,只需将其设为只读 属性 在你的域模型中。
public string RepresentationCode { get; } = $"USER_REPRESENTATION_{Id}";