我使用 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}");
}
}
}