Limity czasu jednostki encji

324

Otrzymuję limity czasu przy użyciu Entity Framework (EF), gdy korzystam z importu funkcji, którego ukończenie zajmuje ponad 30 sekund. Próbowałem następujących czynności i nie udało mi się rozwiązać tego problemu:

Dodałem Default Command Timeout=300000do ciągu połączenia w pliku App.Config w projekcie, który ma plik EDMX, jak sugerowano tutaj .

Tak wygląda mój ciąg połączenia:

<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" />

Próbowałem ustawić CommandTimeout bezpośrednio w moim repozytorium tak:

private TrekEntities context = new TrekEntities();

public IEnumerable<TrekMatches> GetKirksFriends()
{
    this.context.CommandTimeout = 180;
    return this.context.GetKirksFriends();
}

Co jeszcze mogę zrobić, aby uzyskać limit czasu EF? Dzieje się tak tylko w przypadku bardzo dużych zestawów danych. Wszystko działa dobrze z małymi zestawami danych.

Oto jeden z błędów, które otrzymuję:

System.Data.EntityCommandExecutionException: Wystąpił błąd podczas wykonywania definicji polecenia. Zobacz wewnętrzny wyjątek, aby uzyskać szczegółowe informacje. ---> System.Data.SqlClient.SqlException: Upłynął limit czasu. Limit czasu upłynął przed zakończeniem operacji lub serwer nie odpowiada.


OK - mam to działa i to głupie, co się stało. Miałem zarówno ciąg połączenia z, jak Default Command Timeout=300000i CommandTimeout ustawione na 180. Gdy usunąłem Default Command Timeoutciąg połączenia, zadziałało. Zatem odpowiedzią jest ręczne ustawienie CommandTimeout w repozytorium na obiekcie kontekstowym w następujący sposób:

this.context.CommandTimeout = 180;

Najwyraźniej ustawienie limitów czasu w ciągu połączenia nie ma na to wpływu.

Zimorodek
źródło
Usuń & rdquo; z ciągu połączenia
Brian Webster
5
@ hamlin11 W ciągu połączenia EF jest to wymagane do zdefiniowania, która część jest ciągiem połączenia, a która jest metadanymi EF. Pozostaw &quot;w ciągu.
Chev
2
moja sugestia jest taka, że ​​zanim zwiększysz limit czasu, najpierw sprawdzisz, dlaczego EF się kończy. W naszym przypadku zdaliśmy sobie sprawę, że musimy dodać NONCLUSTEREDindeksy do niektórych tabel, co rozwiązało problem przekroczenia limitu czasu.
zulucoda
Pracuję ze wsparciem MS w sprawie problemu z przekroczeniem limitu czasu SQL - wtedy DB jest hostowany na SQL Azure. Powiedziano mi, że wszystkie usługi Azure PaaS (strony PaaS i SQL Azure itp.) Mają uniwersalny limit czasu wynoszący 230 sekund, a to zawsze ma pierwszeństwo, nawet jeśli limit czasu zostanie ustawiony ręcznie. Ma to na celu ochronę zasobów wielokrotnie dzierżawionej infrastruktury PaaS.
Ian Robertson

Odpowiedzi:

552

Znany jest błąd polegający na określaniu domyślnego limitu czasu polecenia w ciągu połączenia EF.

http://bugs.mysql.com/bug.php?id=56806

Usuń wartość z ciągu połączenia i ustaw ją w samym obiekcie kontekstu danych. Działa to, jeśli usuniesz sprzeczną wartość z ciągu połączenia.

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 i poniżej:

this.context.CommandTimeout = 180;
Chev
źródło
5
Jak mogę to osiągnąć za pomocą edmx?
iroel
2
W której wersji EntityFramework jest to naprawione? Nie mogę znaleźć błędu EF.
rudimenter
7
Nie sądzę, że jest to błąd, ale raczej z założenia, zobacz sekcję Uwagi tutaj link
Mick P
3
Ponieważ niektóre ustawienia są w ms, a niektóre w s, sprawdziłem to tutaj , CommandTimeout jest w sekundach.
JabberwockyDecompiler
6
W Entity Framework 7 możesz to ustawić w konstruktorze DbContext / IdentityDbContext:this.Database.SetCommandTimeout(180);
Thomas Hagström
101

Jeśli używasz DbContext, użyj następującego konstruktora, aby ustawić limit czasu komendy:

public class MyContext : DbContext
{
    public MyContext ()
    {
        var adapter = (IObjectContextAdapter)this;
        var objectContext = adapter.ObjectContext;
        objectContext.CommandTimeout = 1 * 60; // value in seconds
    }
}
żagiel
źródło
3
@ErickPetru, więc możesz łatwo zmienić go na inną liczbę minut :), również nie byłbym zaskoczony, gdyby kompilator zoptymalizował to mnożenie!
Joel Verhagen
2
@JoelVerhagen, nie bądź zaskoczony. Oto dobre wyjaśnienie, kiedy nastąpi automatyczna optymalizacja: stackoverflow.com/questions/160848/… . W tym przypadku przypuszczam, że nawet tak się dzieje (ponieważ są to dwie dosłowne wartości), ale szczerze mówiąc, myślę, że kod jest w ten sposób dziwny.
Erick Petrucelli
33
meh ... dzieci głodują ... kogo to obchodzi około 1 * 60?
Timmerz
9
@ErikPetru, w rzeczywistości jest to bardzo powszechna praktyka i sprawia, że ​​kod jest bardziej czytelny.
Calvin,
Jaki jest najlepszy sposób, aby sobie z tym poradzić, biorąc pod uwagę, że moja DbContextklasa pochodna została wygenerowana automatycznie z edmxpliku?
Matt Burland
41

Jeśli używasz DbContexti EF v6 +, możesz alternatywnie użyć:

this.context.Database.CommandTimeout = 180;
Paweł
źródło
13

Zwykle obsługuję moje operacje w ramach transakcji . Jak się przekonałem, nie wystarczy ustawić limit czasu polecenia kontekstu, ale transakcja wymaga konstruktora z parametrem limitu czasu. Musiałem ustawić obie wartości limitu czasu, aby działało poprawnie.

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

Pod koniec funkcji ustawiłem limit czasu komendy na poprzednią wartość w prevto.

Korzystanie z EF6

pillesoft
źródło
W ogóle niezbyt dobre podejście. Kiedyś dodawałem wiele zakresu transakcji i stało się to dla mnie koszmarem w projekcie. Ostatecznie zastąpiono cały zakres transakcji jednym SAVEChanges () w EF 6+. Sprawdź ten coderwall.com/p/jnniww/…
Księżyce
Ta odpowiedź powinna mieć wyższy głos. Próbowałem na różne sposoby, aby zwiększyć limit czasu, ale tylko wtedy, gdy ustawiłem BOTH limit czasu polecenia kontekstu i zakres transakcji, to zadziałało.
Gang
3

Wiem, że działa to bardzo stary wątek, ale EF jeszcze tego nie naprawił. W przypadku osób korzystających z automatycznego generowania DbContextmożna użyć następującego kodu, aby ręcznie ustawić limit czasu.

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;
    }
Shiva N
źródło
3

Jeśli używasz Entity Framework jak ja, powinieneś zdefiniować Limit czasu w klasie Autostart w następujący sposób:

 services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), o => o.CommandTimeout(180)));
parismiguel
źródło
1

Właśnie to sfinansowałem. Może to komuś pomoże:

Więc zaczynamy:

Jeśli używasz LINQ z EF, szukając pewnych dokładnych elementów zawartych na liście, takich jak to:

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

wszystko idzie dobrze, dopóki lista nie zawiera więcej niż jednego identyfikatora.

Problem „przekroczenia limitu czasu” pojawia się, jeśli lista zawiera tylko jeden identyfikator. Aby rozwiązać problem, użyj warunku, aby sprawdzić liczbę identyfikatorów w IdList.

Przykład:

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

Wyjaśnienie:

Po prostu spróbuj użyć Sql Profiler i sprawdź instrukcję Select wygenerowaną przez element Ente frameeork. …

tosjam
źródło