entity framework异步发出上下文或查询?
我的下面的查询有异步问题。 我有单例上下文,我试图执行以下查询:
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)); }
在这个我得到以下错误的间歇性问题:
在先前的异步操作完成之前,在该上下文上开始第二个操作。 使用’await’确保在此上下文上调用另一个方法之前已完成任何异步操作。 任何实例成员都不保证是线程安全的。
我有单身语境
这是你的问题。 DbContext
不是线程安全的,旨在一次执行一个查询。 由于您正在共享DbContext
,因此您可能正在尝试同时调用另一个查询,这在DbContext
术语中并非“合法”。
您甚至可以在ToListAsync
的备注中看到它:
不支持在同一上下文实例上进行多个活动操作。 使用’await’确保在此上下文上调用另一个方法之前已完成任何异步操作。
您应该做的不是通过全局单例重用您的上下文,每次要查询数据库时都创建一个新的上下文。
编辑:
不是通过工厂方法获取单个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(); }
DbContext
应该适用于一个业务事务(工作单元),不多也不少。 业务事务通常是请求,页面或表单。 DbContext不是线程安全的,它保留一个内部实体缓存并跟踪更改,因此您无法在多个请求中共享它。
您真的需要阅读entity framework文档: 使用DbContext 。
我不会为每个存储库创建一个实例,因为业务事务可以操作多个存储库。
您可以在存储库中注入上下文:
public class BaseRepository { private IConfigurationContext context; public BaseRepository(IConfigurationContext context) { this.context = context; } //... }
更改工厂,以便每次都创建一个实例:
public interface IConfigurationContextFactory { IConfigurationContext CreateContext(); } // ... public ConfigurationContext CreateContext() { return new ConfigurationContext(connectionString); }
然后配置依赖项解析程序以在每个工作单元中注入IConfigurationContext
。 假设您正在使用unity实现ASP.NET应用程序。
container.RegisterType( //Instance per http request (unit of work) new PerRequestLifetimeManager(), //Create using factory new InjectionFactory(c => c.Resolve.CreateContext()));
不要忘记在需要时在业务事务结束时调用SaveChangesAsync
:操作成功并且需要保留修改。