Tempo limite da estrutura da entidade

324

Estou recebendo tempos limite usando o Entity Framework (EF) ao usar uma função de importação que leva mais de 30 segundos para ser concluída. Tentei o seguinte e não consegui resolver esse problema:

Eu adicionei Default Command Timeout=300000para a seqüência de conexão no App.Config arquivo no projeto que tem o arquivo EDMX como sugerido aqui .

É assim que minha cadeia de conexão se parece:

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

Tentei definir o CommandTimeout no meu repositório diretamente da seguinte maneira:

private TrekEntities context = new TrekEntities();

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

O que mais posso fazer para que o EF atinja o tempo limite? Isso acontece apenas para conjuntos de dados muito grandes. Tudo funciona bem com pequenos conjuntos de dados.

Aqui está um dos erros que estou recebendo:

System.Data.EntityCommandExecutionException: ocorreu um erro ao executar a definição de comando. Consulte a exceção interna para obter detalhes. ---> System.Data.SqlClient.SqlException: tempo limite expirado. O período de tempo limite decorrido antes da conclusão da operação ou o servidor não está respondendo.


OK - Eu consegui isso e é bobagem o que aconteceu. Eu tinha a string de conexão com Default Command Timeout=300000e o CommandTimeout definido como 180. Quando removi a Default Command Timeoutstring de conexão, ela funcionou. Portanto, a resposta é definir manualmente o CommandTimeout no seu repositório no seu objeto de contexto da seguinte maneira:

this.context.CommandTimeout = 180;

Aparentemente, definir as configurações de tempo limite na cadeia de conexão não tem efeito sobre ela.

idílico
fonte
Remova & quot; da cadeia de conexão
Brian Webster
5
@ hamlin11 Numa cadeia de conexão EF, isso é necessário para definir qual parte é a cadeia de conexão e qual parte são os metadados EF. Deixe &quot;na string.
Chev
2
minha sugestão é que, antes de você aumentar o tempo limite, investigue primeiro para saber por que a EF está atingindo o tempo limite. No nosso caso, percebemos que precisávamos adicionar NONCLUSTEREDíndices a algumas das tabelas, isso resolveu o problema de tempo limite para nós.
Zulucoda
Estou trabalhando com o suporte da Microsoft em um problema de tempo limite do SQL - é quando o banco de dados está hospedado no SQL Azure. Foi-me dito que todos os serviços PaaS do Azure (sites PaaS e SQL Azure etc) têm um tempo limite universal de 230 segundos e isso sempre tem precedência, mesmo se você definir um tempo limite manualmente. Isso serve para proteger os recursos da infraestrutura PaaS com vários arrendatários.
22617 Ian Robertson

Respostas:

552

Há um erro conhecido ao especificar o tempo limite do comando padrão na cadeia de conexão EF.

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

Remova o valor da cadeia de conexão e defina-o no próprio objeto de contexto de dados. Isso funcionará se você remover o valor conflitante da cadeia de conexão.

Entity Framework Core 1.0:

this.context.Database.SetCommandTimeout(180);

Estrutura de Entidades 6:

this.context.Database.CommandTimeout = 180;

Estrutura de Entidades 5:

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

Estrutura de entidade 4 e abaixo:

this.context.CommandTimeout = 180;
Chev
fonte
5
Como posso conseguir isso usando o edmx?
Iroel
2
Em qual versão do EntityFramework isso é corrigido? Não consigo encontrar o bug da EF para ele.
Rudimenter
7
Eu não acredito que isso seja um bug, mas sim por design, consulte a seção Comentários aqui no link
Mick P
3
Como algumas configurações estão em ms e outras em s, procurei aqui , CommandTimeout está em segundos.
precisa
6
No Entity Framework 7, você pode configurá-lo no construtor de DbContext / IdentityDbContext:this.Database.SetCommandTimeout(180);
Thomas Hagström
101

Se você estiver usando um DbContext, use o seguinte construtor para definir o tempo limite do comando:

public class MyContext : DbContext
{
    public MyContext ()
    {
        var adapter = (IObjectContextAdapter)this;
        var objectContext = adapter.ObjectContext;
        objectContext.CommandTimeout = 1 * 60; // value in seconds
    }
}
velejar
fonte
3
@ErickPetru, para que você possa alterá-lo facilmente para um número diferente de minutos :), também não ficaria surpreso se o compilador otimizar essa multiplicação!
Joel Verhagen
2
@ JoelVerhagen, não se surpreenda. Aqui está uma boa explicação de quando a otimização automática ocorre: stackoverflow.com/questions/160848/… . Nesse caso, suponho que isso aconteça (já que são dois valores literais), mas sinceramente acho que o código é meio estranho dessa maneira.
Erick Petrucelli
33
meh ... as crianças estão morrendo de fome ... quem se importa com 1 * 60?
Timmerz 17/07/2013
9
@ErikPetru, essa é realmente uma prática muito comum e torna o código mais legível.
Calvin
Qual é a melhor maneira de lidar com isso, uma vez que minha DbContextclasse derivada foi gerada automaticamente a partir de um edmxarquivo?
Matt Burland
41

Se você estiver usando o DbContextEF v6 +, como alternativa, você pode usar:

this.context.Database.CommandTimeout = 180;
Paulo
fonte
13

Normalmente, eu manuseio minhas operações dentro de uma transação . Como experimentei, não é suficiente definir o tempo limite do comando de contexto, mas a transação precisa de um construtor com um parâmetro de tempo limite. Eu tive que definir os dois valores de tempo limite para que funcionasse corretamente.

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

No final da função, retornei o comando timeout ao valor anterior em prevto.

Usando EF6

pillesoft
fonte
Não é uma boa abordagem. Eu costumava adicionar muito escopo de transação e isso se tornou um pesadelo para mim em um projeto. Eventualmente, substituiu todo o escopo da transação por um único SAVEChanges () no EF 6+. Verifique este coderwall.com/p/jnniww/…
Luas
Esta resposta deve ter maior voto. Tentei de todas as maneiras diferentes aumentar o tempo limite, mas somente quando eu defini o tempo limite do comando de contexto e o escopo da transação, funcionou.
Gangue
3

Eu sei que este é um thread muito antigo em execução, mas ainda assim a EF não corrigiu isso. Para pessoas que usam a geração automática, DbContextuse o código a seguir para definir o tempo limite manualmente.

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
fonte
3

Se você estiver usando o Entity Framework como eu, defina Tempo limite na classe Startup da seguinte maneira:

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

É isso que eu financio. Talvez ajude alguém:

Aqui vamos nos:

Se você usar o LINQ com EF, procurando por alguns elementos exatos contidos na lista como este:

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

tudo está indo bem até que o IdList contenha mais de um ID.

O problema de "tempo limite" será exibido se a lista contiver apenas um ID. Para resolver o problema, use a condição if para verificar o número de IDs na IdList.

Exemplo:

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

Explicação:

Simplesmente tente usar o Sql Profiler e verifique a instrução Select gerada pelo Entity frameeork. ...

tosjam
fonte