【发布时间】:2015-07-30 17:56:14
【问题描述】:
我正在开发一个应用程序来处理公司资源。我们有一个 MS SQL 数据库,并且正在使用 EntityFramework 6.1.3 和 .Net4.5。 现在 DbContext 有异步方法,例如
protected Task<int> SaveChangesAsync();
我知道 DbContext 不是线程安全的,我不想实际调用异步操作以使它们并行执行。但是我需要在轮询数据库时释放我的 GUI 线程。
通常您会使用 await 关键字进行编程,并且“请注意”不要同时调用 2 个异步操作,但应用程序应该始终是最新的。因此,我们有一个服务器连接。现在,每次其他用户更新数据库时,都会向当前正在处理该数据库的所有应用程序发送轮询命令。此轮询命令可以在任何时间执行,因此对于任何用户发起的数据库异步轮询都是一种竞争条件。
我想要做的是将每个任务排在前一个任务之后。但我真的不知道该怎么做,或者这是否是个好主意。 到目前为止,我尝试使用 Task.ContinueWith(),但注意到我的任务永远不会启动,因此我永远等待。
这是目前为止的代码
(_lastRunningTask 在我的 DbContext 继承类中声明并在构造函数中初始化:
_lastRunningTask = Task.Run(() => { Thread.Sleep(1); });
)
private Task _lastRunningTask;
private Task<int> SaveChangesAsyncImpl(CancellationToken cancellationToken)
{
return ValidateEntitiesAsyncImpl().ContinueWith(p => SaveChangesAsync(cancellationToken)).Unwrap();
}
public override int SaveChanges()
{
Task<int> t = _lastRunningTask.ContinueWith(p => SaveChangesAsyncImpl(CancellationToken.None)).Unwrap();
_lastRunningTask = t;
return t.Result;
}
public override Task<int> SaveChangesAsync()
{
return SaveChangesAsync(CancellationToken.None);
}
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken)
{
Task<int> t = _lastRunningTask.ContinueWith(p => SaveChangesAsyncImpl(cancellationToken)).Unwrap();
_lastRunningTask = t;
return t;
}
public Task ValidateEntitiesAsync()
{
return _lastRunningTask = _lastRunningTask.ContinueWith(p => ValidateEntitiesAsyncImpl()).Unwrap();
}
private Task ValidateEntitiesAsyncImpl()
{
return Task.Run(() =>
{
ChangeTracker.DetectChanges();
List<DbEntityEntry> AllEntites = new List<DbEntityEntry>(ChangeTracker.Entries());
try
{
foreach (DbEntityEntry entity in AllEntites)
{
if (entity.State == EntityState.Deleted)
((EntityBase)entity.Entity).readyToDelete();
}
}
catch (ErrorException e)
{
fireError(e);
throw e;
}
catch (Exception e)
{
return;
}
return;
});
}
public Task RevertChangesAsync<TEntity>(CancellationToken token)
where TEntity : EntityBase
{
return _lastRunningTask = _lastRunningTask.ContinueWith(p => RevertChangesAsync<TEntity>(token)).Unwrap();
}
private Task RevertChangesAsyncImpl<TEntity>(CancellationToken token) where TEntity : EntityBase
{
return Task.Run(() => revertDummy<TEntity>(token));
}
private async void revertDummy<TEntity>(CancellationToken token) where TEntity : EntityBase
{
ChangeTracker.DetectChanges();
List<DbEntityEntry<TEntity>> revertEntries = new List<DbEntityEntry<TEntity>>(ChangeTracker.Entries<TEntity>());
foreach (DbEntityEntry entity in revertEntries)
{
await entity.ReloadAsync(token);
}
}
【问题讨论】:
-
我有类似的问题。最终使用 BackGroundworker 进行 SQL 数据库查询,因此我的 Windows 窗体没有锁定。
标签: c# multithreading async-await entity-framework-6 .net-4.5