Тайм-ауты Entity Framework

324

Я получаю тайм-ауты с использованием 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=&quot;
       Data Source=trekdevbox;Initial Catalog=StarTrekDatabase;
       Persist Security Info=True;User ID=JamesTKirk;Password=IsFriendsWithSpock;
       MultipleActiveResultSets=True;Default Command Timeout=300000;&quot;"
    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;

Видимо, установка параметров времени ожидания в строке подключения не влияет на это.

зимородок
источник
Удалить & quot; из строки подключения
Брайан Вебстер
5
@ hamlin11 В строке подключения EF требуется указать, какая часть является строкой подключения, а какая - метаданными EF. Оставьте &quot;в строке.
Chev
2
мое предложение, прежде чем вы увеличите время ожидания, сначала нужно выяснить, почему EF истекает. В нашем случае мы поняли, что нам нужно добавить NONCLUSTEREDиндексы для некоторых таблиц, это решило проблему с тайм-аутом для нас.
zulucoda
Я работаю с поддержкой MS над проблемой истечения времени ожидания SQL - это когда БД размещается в SQL Azure. Мне сказали, что все службы Azure PaaS (веб-сайты PaaS, SQL Azure и т. Д.) Имеют универсальное время ожидания 230 секунд, и оно всегда имеет приоритет, даже если вы устанавливаете время ожидания вручную. Это необходимо для защиты ресурсов мультитенантной инфраструктуры PaaS.
Ян Робертсон,

Ответы:

552

Существует известная ошибка с указанием времени ожидания команды по умолчанию в строке подключения 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;
Chev
источник
5
Как я могу добиться этого с помощью EDMX?
iroel
2
В какой версии EntityFramework это исправлено? Я не могу найти ошибку EF для этого.
Рудиментр
7
Я не считаю , что это ошибка, а по дизайну, см раздел Замечаний здесь ссылка
Mick P
3
Поскольку некоторые настройки указаны в мс, а некоторые в с, я посмотрел их здесь , CommandTimeout за секунды.
JabberwockyDecompiler
6
В Entity Framework 7 вы можете установить это в конструкторе DbContext / IdentityDbContext:this.Database.SetCommandTimeout(180);
Thomas Hagström
101

Если вы используете DbContext, используйте следующий конструктор для установки времени ожидания команды:

public class MyContext : DbContext
{
    public MyContext ()
    {
        var adapter = (IObjectContextAdapter)this;
        var objectContext = adapter.ObjectContext;
        objectContext.CommandTimeout = 1 * 60; // value in seconds
    }
}
Saille
источник
3
@ErickPetru, так что вы можете легко изменить его на другое количество минут :), также я не был бы слишком удивлен, если бы компилятор оптимизировал это умножение!
Джоэл Верхаген
2
@JoelVerhagen, не удивляйся. Вот хорошее объяснение того, когда происходит автоматическая оптимизация: stackoverflow.com/questions/160848/… . В этом случае, я предполагаю, что это даже произойдет (так как они являются двумя буквальными значениями), но, честно говоря, я думаю, что код немного странный в этом смысле.
Эрик Петручелли
33
Мех ... дети голодают ... кого волнует 1 * 60?
Тиммерц
9
@ErikPetru, это на самом деле очень распространенная практика и делает код более читабельным.
Calvin
Каков наилучший способ справиться с этим, если мой DbContextпроизводный класс был автоматически сгенерирован из edmxфайла?
Мэтт Берлэнд
41

Если вы используете DbContextи EF v6 +, в качестве альтернативы вы можете использовать:

this.context.Database.CommandTimeout = 180;
Павел
источник
13

Обычно я выполняю свои операции в рамках транзакции . Как я понял, недостаточно установить тайм-аут команды контекста, но для транзакции нужен конструктор с параметром тайм-аута. Я должен был установить оба значения тайм-аута для его правильной работы.

int? prevto = uow.Context.Database.CommandTimeout;
uow.Context.Database.CommandTimeout = 900;
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromSeconds(900))) {
...
}

В конце функции я установил таймаут команды на предыдущее значение в prevto.

Использование EF6

pillesoft
источник
Не очень хороший подход. Раньше я добавлял много транзакций, и это стало для меня кошмаром в проекте. В итоге заменил всю область транзакции одним SAVEChanges () в EF 6+. Проверьте это coderwall.com/p/jnniww/…
Лун
Этот ответ должен иметь более высокий голос. Я пытался разными способами увеличить время ожидания, но только когда я установил ОБА контекстного командного времени и области действия транзакции, это сработало.
Банда
3

Я знаю, что это очень старая ветка, но 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;
    }
Шива Н
источник
3

Если вы используете Entity Framework, как я, вы должны определить время ожидания в классе запуска следующим образом:

 services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), o => o.CommandTimeout(180)));
parismiguel
источник
1

Это то, что я финансировал. Может быть, это кому-то поможет

Итак, поехали:

Если вы используете LINQ с EF, ищите некоторые точные элементы, содержащиеся в списке, например:

await context.MyObject1.Include("MyObject2").Where(t => IdList.Contains(t.MyObjectId)).ToListAsync();

все идет хорошо, пока IdList не содержит более одного 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. ...

tosjam
источник