繁体   English   中英

异步EF任务的同步

[英]Syncronization of async EF Tasks

我正在研究处理公司资源的应用程序。 我们有一个MS SQL数据库,并且正在使用EntityFramework 6.1.3和.Net4.5。 现在,DbContext具有异步方法,例如

protected Task<int> SaveChangesAsync();

我知道DbContext不是线程安全的,并且我不想实际调用Async操作并打算并行执行它们。 但是我需要在轮询数据库时释放GUI线程。

通常,您会使用await关键字进行编程,并且“小心点”不要同时调用2个Async操作,但应用程序应该始终是最新的。 因此,我们有一个服务器连接。 现在,每当其他用户更新数据库时,就会向该数据库上当前正在运行的所有应用程序发送轮询命令。 该轮询命令可以随时随地发生,因此任何用户发起的数据库异步轮询都将产生竞争条件。

我要做的是将每个任务排在上一个任务之后。 但是我真的不知道怎么做,或者那是否是个好主意。 到目前为止,我尝试使用Task.ContinueWith(),但注意到我的任务从未启动,因此我永远等待。

这是到目前为止的代码
(_lastRunningTask在我的DbContext inhereing类中声明,并在构造函数中使用初始化:

_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);
        }
    }

我知道DbContext不是线程安全的,并且我不想实际调用Async操作并打算并行执行它们。

DbContext确实不是线程安全的。 但是,这并不意味着您同时查询它。 使用async没有线程 您无需使用Task.Run来完成任何您想做的工作。 充分利用Entity Framework提供的自然异步API。

只要为每个查询启动DbContext的新实例,就可以了。

例如:

private async Task RevertDummyAsync<TEntity>(
    Entity entity, CancellationToken token) where TEntity : EntityBase
{
    using (var context = new SomeDbContext())
    {
        ChangeTracker.DetectChanges();
        List<DbEntityEntry<TEntity>> revertEntries = 
            new List<DbEntityEntry<TEntity>>(ChangeTracker.Entries<TEntity>());

        foreach (DbEntityEntry entity in revertEntries)
        {
            await entity.ReloadAsync(token);
        }
    }
}

然后可以在实体集合上调用它:

var collections = new List<Entity>();
var tasks = collections.Select(x => RevertDummyAsync<Entity>(x));
await Task.WhenAll(tasks);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM