在异步调用中使用DbContext的问题

问题描述 投票:0回答:0

我使用 Entity Framework Core 与数据库交互的代码有问题。我在

DbContext
类的构造函数中创建了一个
UnitOfWork
的实例,并通过存储库方法访问它。但是,当我第二次调用 Invoke 时,出现错误“在前一个操作完成之前,在此上下文实例上启动了第二个操作。这通常是由不同的线程同时使用同一个 DbContext 实例引起的。”

我已经尝试通过使用

using
创建临时
DbContext
实例来解决这个问题,但它没有帮助。我也尝试过使用 async/await 来等待前面的操作完成,但也没有用。

我不知道如何解决这个问题。也许你们中的一些人遇到过同样的问题并且知道如何解决?如果有任何帮助,我将不胜感激!

我的代码

BotContext:

public class BotContext : DbContext
{
    public DbSet<ChatUser> ChatUsers { get; set; }
    public DbSet<TelegramChat> TelegramChats { get; set; }
    public DbSet<TelegramUser> TelegramUsers { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        string connString;
        // ...
        optionsBuilder.UseNpgsql(connString);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfigurationsFromAssembly(typeof(BotContext).Assembly);
    }

    public string GetHashCode()
    {
        return base.ContextId.InstanceId.ToString();
    }
}

工作单位:

public class UnitOfWork : IUnitOfWork
{
    private readonly ConcurrentDictionary<Type, object> _repsDictionary;
    internal static readonly ConcurrentDictionary<Type, object> cash = new();
    private static readonly ConcurrentDictionary<string, object> _fieldDictionary = new();
    private readonly BotContext _dbContext;

    public UnitOfWork()
    {
        _dbContext = new BotContext();
        _repsDictionary = new ConcurrentDictionary<Type, object>();
    }

    public IRepository<TEntity> GetRepository<TEntity>()
        where TEntity : class, IBaseEntity
    {
        if (cash.ContainsKey(typeof(TEntity)))
            return _repsDictionary.GetOrAdd(typeof(TEntity),
                x => new Repository<TEntity>(_dbContext.Set<TEntity>())) as IRepository<TEntity>;
        var rep = _dbContext.Set<TEntity>();
        cash.GetOrAdd(typeof(TEntity), rep.ToArray());
        return _repsDictionary.GetOrAdd(typeof(TEntity),
            x => new Repository<TEntity>(rep)) as IRepository<TEntity>;
    }

    public async Task SaveChangesAsync()
    {
        Console.WriteLine($"Invoke SaveChangesAsync in context with hashcode: {_dbContext.GetHashCode()}");
        await _dbContext.SaveChangesAsync();
    }

    public static void SetField(string name, object obj)
    {
        _fieldDictionary[name] = obj;
    }

    public static T GetField<T>(string name)
    {
        return (T)_fieldDictionary[name];
    }

    private bool _disposed;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual async Task Dispose(bool disposing)
    {
        Console.WriteLine($"dispose call for UoW with hashcode {this.GetHashCode()} and contextId {_dbContext.GetHashCode()}");
        if (_disposed) return;

        if (disposing)
        {
            await _dbContext.DisposeAsync();
        }

        _disposed = true;
    }

    ~UnitOfWork() => Dispose(false);
}

出现问题的代码:

public class DALTestCommand : IConsoleCommand
{
    public string CommandName { get; set; } = "daltest";
    public string CommandDescription { get; set; } = "DAL Testing";
    public async Task Invoke(ControlConsole console, TelegramBotClient botClient)
    {
        using var uow = new UnitOfWork();
        var rep = uow.GetRepository<TelegramUser>();
        var entry = TelegramUser.Create(new Random().NextInt64(), "@TEST");
        rep.Add(entry);
        await uow.SaveChangesAsync();
    }
}

调用:

public async Task StartConsole()
{
    Console.WriteLine("Type help to get available commands");
    while (_botWorked)
    {
        var msg = await Console.In.ReadLineAsync();
        if (string.IsNullOrEmpty(msg)) continue;
        try
        {
            if (_commands.TryGetValue(msg.ToLower().Trim(), out var action))
            {
                await action.Invoke(this, _botClient);
            }
            else
            {
                ConsoleLogger.LogError("Command not found!");
            }
        }
        catch (Exception e)
        {
            ConsoleLogger.LogError($"{e.Message}");
        }
    }
}
c# .net async-await entity-framework-core
© www.soinside.com 2019 - 2024. All rights reserved.