从数据库中读取数据时出现此错误:
在上一个操作之前,在此上下文中启动了第二个操作 完成。不保证任何实例成员都是线程安全的。
我有以下ApplicationContext.cs:
public class ApplicationContext : Microsoft.EntityFrameworkCore.DbContext
{
public ApplicationContext(DbContextOptions<ApplicationContext> options)
: base(options)
{ }
public DbSet<MyClass> MyClasses{ get; set; }
}
以下ApplicationContextFactory.cs
public class ApplicationContextFactory : IDesignTimeDbContextFactory<ApplicationContext>
{
public ApplicationContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<ApplicationContext>();
var connection = "myConnectionString";
builder.UseSqlServer(connection);
return new ApplicationContext(builder.Options);
}
}
以下ServiceLoader.cs(我声明DI):
public static class ServiceLoader
{
public static void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IRepository, Repository>();
var connection = "myConnectionString";
services.AddDbContext<ApplicationContext>(options => options.UseSqlServer(connection));
}
}
最后是以下Repository,抛出异常:
public class Repository : IRepository
{
private ApplicationContext _db;
public Repository (ApplicationContext db)
{
_db = db;
}
public List<MyClass> Get()
{
_db.MyClasses.ToList();
}
}
我还尝试将Repository声明为Transient而不是Singleton,但抛出了类似的错误
&#39;尝试在配置上下文时使用上下文。 DbContext实例不能在OnConfiguring内使用,因为此时仍在配置它。如果在上一个操作完成之前在此上下文上启动第二个操作,则会发生这种情况。任何实例成员都不能保证是线程安全的。&#39;
有关如何解决此问题的任何想法?谢谢!
答案 0 :(得分:1)
您可以在Get()函数周围包装一个异步任务,然后等待结果:
public async Task<List<MyClass>> Get()
{
return await _db.MyClasses.ToListAsync();
}
答案 1 :(得分:0)
就我而言,我发现以下信息很有帮助:
https://docs.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext
并在启动时使用重载的AddDbContext方法将我的Db上下文的生存期范围更改为瞬态:
services.AddDbContext<MyAppDbContext>(options => {
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection"));
}, ServiceLifetime.Transient);
答案 2 :(得分:0)
我写了一个使用队列的解决方案。它仍然是单线程的,但是您可以从不同的线程调用它。
public class ThreadSafeDataContext
{
private Thread databaseThread;
private Queue<PendingQuery> pendingQueries = new Queue<PendingQuery>();
private DatabaseContext db = new DatabaseContext();
private bool running = true;
public ThreadSafeDataContext()
{
databaseThread = new Thread(new ThreadStart(DoWork));
databaseThread.Start();
}
public void StopService()
{
running = false;
}
private void DoWork()
{
while(running)
{
if (pendingQueries.Count > 0)
{
// Get and run query
PendingQuery query = pendingQueries.Dequeue();
query.result = query.action(db);
query.isFinished = true;
}
else
{
Thread.Sleep(1); // Waiting for queries
}
}
}
public T1 Query<T1>(Func<DatabaseContext, T1> action)
{
Func<DatabaseContext, object> a = (DatabaseContext db) => action(db);
PendingQuery query = new PendingQuery(a);
pendingQueries.Enqueue(query);
while (!query.isFinished) {
Thread.Sleep(1); // Wait until query is finished
}
return (T1)query.result;
}
}
class PendingQuery
{
public Func<DatabaseContext, object> action;
public bool isFinished;
public object result;
public PendingQuery(Func<DatabaseContext, object> action)
{
this.action = action;
}
}
然后,您可以使用以下命令从不同的线程运行查询:
TeamMembers teamMembers = threadSafeDb.Query((DatabaseContext c) => c.team.ToArray())