我的下面的查询有异步问题.我有单例上下文,我试图执行以下查询:
var query = await (from parent in Context.ParentTable join child in Context.ChildTable on parent.ID equals child.ID into allResult from ResultValue in allResult.DefaultIfEmpty() where ResultValue.TenantId == tenantId select new Result { Code = parent.Code,Type = parent.Type,ID = ResultValue == null ? 0 : ResultValue.Id }).ToListAsync();
我的单例上下文如下所示:
public class BaseRepository { private readonly IConfigurationContextFactory configurationContextFactory; private IConfigurationContext context; protected IConfigurationContext Context { get { return context ?? (context = configurationContextFactory.Context); } } public BaseRepository(IConfigurationContextFactory configurationContextFactory) { this.configurationContextFactory = configurationContextFactory; } }
配置上下文工厂返回Context,如下所示:
private ConfigurationContext Get() { logger.WriteEntrySync(LogLevel.Information,null != context ? "Config Context: Using existing context." : "Config Context: Wiil create new context."); return context ?? (context = new ConfigurationContext(connectionString)); }
在此我得到以下错误的间歇性问题:
A second operation started on this context before a prevIoUs
asynchronous operation completed. Use ‘await’ to ensure that any
asynchronous operations have completed before calling another method
on this context. Any instance members are not guaranteed to be thread
safe.
解决方法
I have singleton context
这是你的问题. DbContext不是线程安全的,旨在一次执行一个查询.由于您正在共享DbContext,因此您可能尝试同时调用另一个查询,这在DbContext术语中并非“合法”.
您甚至可以在remarks of ToListAsync
中看到它:
Multiple active operations on the same context
instance are not supported. Use ‘await’ to ensure that any
asynchronous operations have completed before calling another method
on this context.
您应该做的不是通过全局单例重复使用您的上下文,每次要查询数据库时都创建一个新的上下文.
编辑:
不是通过工厂方法获取单个Context,只需为每个查询分配一个新的:
using (var context = new ConfigurationContext(connectionString)) { var query = await (from feature in context.Features join featureFlag in context.FeatureFlags on feature.FeatureId equals featureFlag.FeatureId into allFeatures from featureFlagValue in allFeatures.DefaultIfEmpty() where featureFlagValue.TenantId == tenantId select new BusinessEntities.FeatureFlag { Code = feature.Code,Type = feature.Type,FeatureFlagId = featureFlagValue == null ? 0 : featureFlagValue.FeatureFlagId }).ToListAsync(); }