Часи очікування рамки сутності


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();
}

Що ще я можу зробити, щоб домогтися відліку часу від часу? Це відбувається лише для дуже великих наборів даних. З невеликими наборами даних все працює добре.

Ось одна з помилок, які я отримую:

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;в рядку.
Шев

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);

Сутність 6:

this.context.Database.CommandTimeout = 180;

Сутність 5:

((IObjectContextAdapter)this.context).ObjectContext.CommandTimeout = 180;

Entity Framework 4 і нижче:

this.context.CommandTimeout = 180;

5
Як я можу досягти цього за допомогою edmx?
iroel

2
У якій версії EntityFramework це виправлено? Я не можу знайти помилку EF для цього.
рудиметр

7
Я не вірю, що це помилка, але, скоріше за дизайном, дивіться розділ "Зауваження" тут за посиланням
Mick P

3
Оскільки деякі налаштування є у ms, а деякі у s, я переглянув це тут , 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
    }
}

3
@ErickPetru, тому ви можете легко змінити його на різну кількість хвилин :), також я не надто здивуюсь, якщо компілятор оптимізує це множення!
Джоель Верхаген

2
@JoelVerhagen, не дивуйся. Ось гарне пояснення , коли відбувається автоматична оптимізація: stackoverflow.com/questions/160848 / ... . У цьому випадку я гадаю, що це навіть трапляється (оскільки вони є двома буквальними значеннями), але, чесно кажучи, я думаю, що код таким чином дивно.
Ерік Петручеллі

33
Мех ... діти голодують ... кого турбує про 1 * 60?
Тіммерз

9
@ErikPetru, це насправді дуже поширена практика і робить код більш читабельним.
Кальвін

Який найкращий спосіб впоратися з цим, враховуючи, що мій 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


Зовсім не хороший підхід. Я раніше додав велику кількість транзакцій, і це стало для мене кошмаром у проекті. Врешті-решт замінив усю область транзакцій однією SAVEChanges () в EF 6+. Перевірте coderwall.com/p/jnniww / ...
місяця

Ця відповідь повинна мати більш високий голос. Я спробував усі різні способи збільшити час очікування, але лише тоді, коли я встановив BOTH контекстну команду timeout та область транзакцій, тоді це спрацювало.
Банда

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, як я, вам слід визначити Time Out в класі запуску наступним чином:

 services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), o => o.CommandTimeout(180)));

1

Це те, що я фінансую. Можливо, комусь це допоможе:

Отже, ми йдемо:

Якщо ви використовуєте LINQ з EF, шукайте деякі точні елементи, що містяться у цьому списку:

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

все йде добре, поки IdList не містить більше одного Id.

Проблема "тайм-аут" з'являється, якщо список містить лише один ідентифікатор. Щоб вирішити проблему, використовуйте, якщо умова перевірити кількість ідентифікаторів в 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. …

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.