【问题标题】:DbContext not update when multiple requests are sent in a short time短时间内发送多个请求时,DbContext 不更新
【发布时间】:2018-03-16 18:04:05
【问题描述】:

目前我正在使用 angularjs 和 web api 2 为我的公司开发一个 web 系统。

在系统中,我们允许用户使用api将帐户添加到数据库中。 这是它的流程:

  • 调用 api/user 将用户添加到数据库中。

  • 添加带有特定信息的用户信息:

    • Id(由 DB 自动生成)
    • RepresentationCode(通过连接 USER_REPRESENTATION_{MaxUserIndex} 计算得到

我举个例子,假设数据库是空的。

  • 同时调用 api/user 20 次。

  • 这些是创建到数据库中的记录。

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 asp.net-web-api2 inversion-of-control autofac object-lifetime


【解决方案1】:

您的代码不起作用,因为多个连续请求最终可能会获得相同的 iMaxUserIndex 值。

例如,请求 A 命中你的控制器并执行这一行:

var iMaxUserIndex = users.Max(x => (int?)x.Id) ?? 0;

然后,请求 B 到达您的控制器并在请求 A 的线程添加实体并保存数据库之前执行上面的同一行。结果是两个请求具有相同的iMaxUserIndex 值。

设置RepresentationCode 变量的最简单方法是将其设为数据库中的计算列,或者如果数据库中不需要该列,只需将其设为域模型中的只读属性即可。

public string RepresentationCode { get; } = $"USER_REPRESENTATION_{Id}";

【讨论】:

  • 感谢您的解决方案。我已经关注了这个关于计算列的问题。目前,它工作正常:)
猜你喜欢
  • 2022-01-01
  • 1970-01-01
  • 2020-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-22
  • 2021-06-04
相关资源
最近更新 更多