ECMAScript 6 имеет «генераторы», которые позволяют вам легко программировать в асинхронном стиле.
function* myGenerator() {
const callback = yield;
let [response] = yield $.ajax("https://stackoverflow.com", {complete: callback});
console.log("response is:", response);
// examples of other things you can do
yield setTimeout(callback, 1000);
console.log("it delayed for 1000ms");
while (response.statusText === "error") {
[response] = yield* anotherGenerator();
}
}
Для запуска вышеуказанного кода вы делаете это:
const gen = myGenerator(); // Create generator
gen.next(); // Start it
gen.next((...args) => gen.next([...args])); // Set its callback function
Если вам нужно настроить таргетинг на браузеры, которые не поддерживают ES6, вы можете запустить код через Babel или short-compiler для генерации ECMAScript 5.
Обратный вызов ...args
завернут в массив и разрушен, когда вы их читаете так что шаблон может справиться с обратными вызовами, которые имеют несколько аргументов. Например, с узлом fs :
const [err, data] = yield fs.readFile(filePath, "utf-8", callback);
A 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
на единицу работы. Предположим, вы работаете над приложением ASP.NET, используя единство.
container.RegisterType<IConfigurationContext>(
//Instance per http request (unit of work)
new PerRequestLifetimeManager(),
//Create using factory
new InjectionFactory(c => c.Resolve<IConfigurationContextFactory>.CreateContext()));
Не забудьте позвонить SaveChangesAsync
в конце вашей бизнес-транзакции, когда это необходимо: операция выполнена успешно, а модификации должны быть сохраняется.
У меня есть singleton context
blockquote>Это ваша проблема.
DbContext
не является потокобезопасным и предназначен для выполнения одного запроса за раз. Поскольку вы делитесь своимDbContext
, вы, вероятно, пытаетесь одновременно вызвать другой запрос, который не является «законным» в терминахDbContext
.Вы даже можете увидеть его в замечания
ToListAsync
:Несколько активных операций в одном экземпляре контекста не поддерживаются. Используйте 'await', чтобы убедиться, что какие-либо асинхронные операции были выполнены до вызова другого метода в этом контексте.
blockquote>То, что вы должны делать, не повторяет использование вашего контекста с глобальный синглтон, создавая новый контекст каждый раз, когда вы хотите запросить свою базу данных.
Изменить:
Вместо того, чтобы получить один
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(); }