Тайм-ауты Entity Framework
Я получаю тайм-ауты с использованием Entity Framework (EF) при использовании импорта функций, выполнение которого занимает более 30 секунд. Я попытался следующее и не смог решить эту проблему:
я добавил Default Command Timeout=300000
к строке подключения в файле App.Config в проекте, который имеет файл EDMX, как предлагается здесь.
Вот как выглядит моя строка подключения:
<add
name="MyEntityConnectionString"
connectionString="metadata=res://*/MyEntities.csdl|res://*/MyEntities.ssdl|
res://*/MyEntities.msl;
provider=System.Data.SqlClient;provider connection string="
Data Source=trekdevbox;Initial Catalog=StarTrekDatabase;
Persist Security Info=True;User ID=JamesTKirk;Password=IsFriendsWithSpock;
MultipleActiveResultSets=True;Default Command Timeout=300000;""
providerName="System.Data.EntityClient" />
Я попытался установить CommandTimeout в моем репозитории, например, так:
private TrekEntities context = new TrekEntities();
public IEnumerable<TrekMatches> GetKirksFriends()
{
this.context.CommandTimeout = 180;
return this.context.GetKirksFriends();
}
Что еще я могу сделать, чтобы получить EF от тайм-аута? Это происходит только для очень больших наборов данных. Все отлично работает с небольшими наборами данных.
Вот одна из ошибок, которые я получаю:
System.Data.EntityCommandExecutionException: произошла ошибка при выполнении определения команды. Смотрите внутреннее исключение для деталей. ---> System.Data.SqlClient.SqlException: истекло время ожидания. Время ожидания истекло до завершения операции или сервер не отвечает.
ОК - у меня это работает, и глупо, что случилось. У меня была как строка подключения с Default Command Timeout=300000
и CommandTimeout установлен на 180. Когда я удалил Default Command Timeout
из строки подключения, это сработало. Таким образом, ответ заключается в том, чтобы вручную установить CommandTimeout в вашем хранилище для вашего объекта контекста следующим образом:
this.context.CommandTimeout = 180;
Видимо, установка параметров времени ожидания в строке подключения не влияет на это.
12 ответов
Существует известная ошибка с указанием времени ожидания команды по умолчанию в строке подключения EF.
http://bugs.mysql.com/bug.php?id=56806
Удалите значение из строки подключения и установите его для самого объекта контекста данных. Это будет работать, если вы удалите конфликтующее значение из строки подключения.
Entity Framework Core 1.0:
this.context.Database.SetCommandTimeout(180);
Entity Framework 6:
this.context.Database.CommandTimeout = 180;
Entity Framework 5:
((IObjectContextAdapter)this.context).ObjectContext.CommandTimeout = 180;
Entity Framework 4 и ниже:
this.context.CommandTimeout = 180;
Если вы используете DbContext, используйте следующий конструктор для установки времени ожидания команды:
public class MyContext : DbContext
{
public MyContext ()
{
var adapter = (IObjectContextAdapter)this;
var objectContext = adapter.ObjectContext;
objectContext.CommandTimeout = 1 * 60; // value in seconds
}
}
Если вы используете DbContext
и EF v6+, в качестве альтернативы вы можете использовать:
this.context.Database.CommandTimeout = 180;
Если вы используете Entity Framework, как я, вы должны определить время ожидания в классе запуска следующим образом:
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), o => o.CommandTimeout(180)));
Обычно я выполняю свои операции в рамках транзакции. Как я уже понял, недостаточно установить тайм-аут команды контекста, но для транзакции нужен конструктор с параметром тайм-аута. Я должен был установить оба значения времени ожидания для его правильной работы.
int? prevto = uow.Context.Database.CommandTimeout;
uow.Context.Database.CommandTimeout = 900;
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromSeconds(900))) {
...
}
В конце функции я установил таймаут команды на предыдущее значение в prevto.
Использование EF6
В .Net Core (NetCore) используйте следующий синтаксис, чтобы изменить время ожидания с 30 секунд по умолчанию на 90 секунд:
public class DataContext : DbContext
{
public DataContext(DbContextOptions<DataContext> options) : base(options)
{
this.Database.SetCommandTimeout(90); // <-- 90 seconds
}
}
Я знаю, что это очень старая ветка, но EF не исправил это. Для людей, использующих сгенерированный автоматически DbContext
Можно использовать следующий код, чтобы установить время ожидания вручную.
public partial class SampleContext : DbContext
{
public SampleContext()
: base("name=SampleContext")
{
this.SetCommandTimeOut(180);
}
public void SetCommandTimeOut(int Timeout)
{
var objectContext = (this as IObjectContextAdapter).ObjectContext;
objectContext.CommandTimeout = Timeout;
}
Это то, что я финансировал. Может быть, это кому-то поможет
Итак, поехали:
Если вы используете LINQ с EF, ищите некоторые точные элементы, содержащиеся в списке, например:
await context.MyObject1.Include("MyObject2").Where(t => IdList.Contains(t.MyObjectId)).ToListAsync();
все идет хорошо, пока IdList не содержит более одного Id.
Проблема "тайм-аут" возникает, если список содержит только один Id. Для решения проблемы используйте условие if для проверки количества идентификаторов в IdList.
Пример:
if (IdList.Count == 1)
{
result = await entities. MyObject1.Include("MyObject2").Where(t => IdList.FirstOrDefault()==t. MyObjectId).ToListAsync();
}
else
{
result = await entities. MyObject1.Include("MyObject2").Where(t => IdList.Contains(t. MyObjectId)).ToListAsync();
}
Объяснение:
Просто попробуйте использовать Sql Profiler и проверьте оператор Select, сгенерированный Entity frameeork....
Для Entity framework 6 я использую эту аннотацию и отлично работает.
public partial class MyDbContext : DbContext
{
private const int TimeoutDuration = 300;
public MyDbContext ()
: base("name=Model1")
{
this.Database.CommandTimeout = TimeoutDuration;
}
// Some other codes
}
Параметр CommandTimeout представляет собой целое число, допускающее значение NULL, которое устанавливает значения тайм-аута в секундах, если вы установите значение NULL или не установите, будет использоваться значение по умолчанию используемого вами поставщика.
Есть 2 параметра тайм-аута, которые вы можете установить в строке подключения.
Время ожидания =300;CommandTimeout=300;
Host=localhost;Port=5432;database=mydatabase;username=postgres;password=postgres;Timeout=300;CommandTimeout=300;
один для команды и один для соединения.
Добавление следующего к моей хранимой процедуре, решило мной ошибку тайм-аута:
SET NOCOUNT ON;
SET ARITHABORT ON;
Если вы используете DbContext и EF v6+, вы можете использовать свойство CommandTimeout
this.context.Database.CommandTimeout = 180;