实体框架异步发出上下文或查询?

Rus*_*sty 6 c# asynchronous entity-framework async-await

我的下面的查询有异步问题.我有单例上下文,我试图执行以下查询:

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();
Run Code Online (Sandbox Code Playgroud)

我的单例上下文如下所示:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

配置上下文工厂返回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));
}
Run Code Online (Sandbox Code Playgroud)

在此我得到以下错误的间歇性问题:

在先前的异步操作完成之前,在该上下文上开始第二操作.使用'await'确保在此上下文上调用另一个方法之前已完成任何异步操作.任何实例成员都不保证是线程安全的.

Yuv*_*kov 21

我有单身语境

这是你的问题.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();
}
Run Code Online (Sandbox Code Playgroud)


Gui*_*ume 9

A DbContext应该适用于一项商业交易(工作单位),不能少于此.业务事务通常是请求,页面或表单.DbContext不是线程安全的,它保留一个内部实体缓存并跟踪更改,因此您无法在多个请求中共享它.

您真的需要阅读实体框架文档:使用DbContext.

我不会为每个存储库创建一个实例,因为业务事务可以操作多个存储库.

您可以在存储库中注入上下文:

public class BaseRepository
{
    private IConfigurationContext context;
    public BaseRepository(IConfigurationContext context)
    {
        this.context = context;
    }
    //...
}
Run Code Online (Sandbox Code Playgroud)

更改工厂,以便每次都创建一个实例:

public interface IConfigurationContextFactory
{
    IConfigurationContext CreateContext();
}

// ...
public ConfigurationContext CreateContext()
{
    return new ConfigurationContext(connectionString);
}
Run Code Online (Sandbox Code Playgroud)

然后配置依赖项解析程序以注入IConfigurationContext每个单元的工作.假设您正在使用统一的ASP.NET应用程序.

container.RegisterType<IConfigurationContext>(
    //Instance per http request (unit of work)
    new PerRequestLifetimeManager(),
    //Create using factory
    new InjectionFactory(c => c.Resolve<IConfigurationContextFactory>.CreateContext()));
Run Code Online (Sandbox Code Playgroud)

不要忘记在需要SaveChangesAsync时在业务事务结束时调用:操作成功并且需要保持修改.