我得到了这个错误:"System. InvalidOperationException:'在上一个操作完成之前,在此上下文实例上启动了第二个操作.这通常是由不同线程并发使用同一个DbContext实例造成的.

这是我的服务代码:

public async Task<IQueryable<GetAllUsersDTO>> UsersById(Guid userId, CancellationToken cancellationToken)
{
try
{
    var Log = await _db.Users
                        .Include(x => x.University)
                        .Include(x => x.Fields)
                        .Where(x => x.UserId == userId)
                        .OrderByDescending(x => x.CreatedAt)
                        .AsNoTracking()
                        .ToListAsync();

    var logsDTO = await Task.WhenAll(Log.Select(async x =>
    {
        var userInDb = await _db.Users.FindAsync((Guid)x.UserId); 
        var user = await _userService.GetDirectoryInformation(userInDb, cancellationToken);
        return new GetAllUsersDTO()
        {
            Description = x.Description,
            PostDate = x.PostDate,
            Id = x.Id,
            RecieveUserId = x.RecieveUserId,
            UniversityId = x.UniversityId,
            IsVisible = x.IsVisible,
            IsApproved = x.IsApproved,
            UserIdOpen = x.UserId,
            UserName = user.UserName,
            LogTitle = x.LogTitle,
            LogNr = x.LogNr,
            Email = user.Email,
        };
    }));

    return logsDTO.AsQueryable();
}
catch (Exception ex)
{
    Console.WriteLine("Error=", ex.Message);
    throw;
}
}

这就是我在这个服务中注入DataContext的方式:

private readonly DataContext _db;
public UserService(DataContext context) : base(context)
{
 _db = context;
}

注意:此服务仅在日志(log)列表仅返回一个数据时才起作用.但是当它返回多个数据时,它会触发错误.

我试着用ServiceLifetime.Scoped配置依赖注入设置,结果如下所示:

builder.Services
    .AddDbContext<DataContext>(opt =>
        opt.UseSqlServer(builder.Configuration.GetConnectionString("connString"))
        ,ServiceLifetime.Scoped
    );

推荐答案

注意:此服务仅在日志(log)列表仅返回一个数据时才起作用.但是当它返回多个数据时,它会触发错误.

_db.Users.FindAsync和潜在的GetDirectoryInformation(似乎它也可以使用/使用数据库)是问题,如下:

var logsDTO = await Task.WhenAll(Log.Select(async x =>
{
    var userInDb = await _db.Users.FindAsync((Guid)x.UserId); 
    var user = await _userService.GetDirectoryInformation(userInDb, cancellationToken);
    // ...
}

将调度执行尽可能多的任务,因为有日志(log)并行.EF Core数据库上下文不应该同时从不同的线程使用.就这样

"直接"解决办法:

  1. 移动获取初始查询中的所有数据(var Log = await _db.Users ...),并完全删除_userService.GetDirectoryInformationTask.WhenAll(Log.Select的使用(我认为这是最好的行动方针)
  2. 在每个任务中创建内部作用域,并在那里解析上下文/_userService

另外请注意,由于您收集单个用户的日志(log),因此完全没有理由在多个线程中查询它.即使出于某种原因,你不想(或不能)只使用Select来构建结果,即:

await _db.Users
    .Where(x => x.UserId == userId)
    .OrderByDescending(x => x.CreatedAt)
    .Select(x => new GetAllUsersDTO
    {
        Description = x.Description,
        // ...
        UserName = x.User.UserName,
        Email = x.User.Email,
    })
    .ToListAsync();

然后只需取一次数据,就可以了:

var Log = ...; // your original query
var userInDb = await _db.Users.FindAsync(userId); 
var user = await _userService.GetDirectoryInformation(userInDb, cancellationToken);
var result = Logs
    .Select(x => new GetAllUsersDTO {...}) // use user, no async/awaits in the select
// ...

Csharp相关问答推荐

我应该将新的httpReportMessage()包装在using声明中吗?

将委托传递到serviceccollection c#web API

在发布表单时绑定包含附加(嵌套)列表的对象列表的正确语法是什么

如何在没有额外副本的情况下将存储在IntPtr下的原始图像数据写入WinUI3中的Image控件?

有没有办法使.NET 6应用程序在特定的.NET 6运行时版本上运行

如何在ASP.NET Core8中启用REST应用程序的序列化?

单元测试:模拟返回空

在C#中,将两个哈希集连接在一起的时间复杂度是多少?

确定System.Text.Json序列化中是否无法识别Type

GODOT 4向C#中的字符串参数发送信号以等待

C#多键字典和TryGetValue

Azure函数-在外部启动类中生成配置时出错

Celler ArgumentExpression是否期望在所有情况下都捕获允许空值的运算符?

如何从Azure函数使用Graph API(SDK 5.35)中的[FindMeetingTimes]

当我手动停止和关闭系统并打开时,Windows服务未启动

Azure函数正在返回值列表,但该列表在Chrome中显示为空

使DefaultIfEmpty返回空

Azure队列触发器未使用隔离的工作进程执行

ASP.NET核心中的授权,如何在DbContext启动之前提供租用ID

同时通过多个IEumable<;T&>枚举