엔터티 프레임 워크 시간 초과


324

완료하는 데 30 초 이상 걸리는 함수 가져 오기를 사용할 때 Entity Framework (EF)를 사용하여 시간 초과가 발생합니다. 다음을 시도했지만이 문제를 해결할 수 없었습니다.

여기에 제안 된대로 EDMX 파일이있는 프로젝트 Default Command Timeout=300000App.Config 파일에 연결 문자열을 추가 했습니다 .

내 연결 문자열은 다음과 같습니다.

<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 : 시간 초과가 만료되었습니다. 작업이 완료되기 전에 시간 초과 기간이 경과했거나 서버가 응답하지 않습니다.


OK-나는이 일을했고 바보 일이 일어났습니다. 연결 문자열이 Default Command Timeout=300000있고 CommandTimeout이 180으로 설정되었습니다 Default Command Timeout. 연결 문자열에서 연결 문자열을 제거하면 작동했습니다. 따라서 정답은 컨텍스트 객체의 저장소에서 CommandTimeout을 수동으로 설정하는 것입니다.

this.context.CommandTimeout = 180;

연결 문자열에서 시간 초과 설정을 설정해도 영향을 미치지 않습니다.


& quot; 연결 문자열에서
Brian Webster


5
@ hamlin11 EF 연결 문자열에서 연결 문자열이 어느 부분이고 어떤 부분이 EF 메타 데이터인지를 정의하는 데 필요합니다. 줄에 그대로 두십시오 &quot;.
Chev

2
내 제안은 EF가 시간 초과되는 이유를 확인하기 위해 시간 초과를 먼저 조사하는 것입니다. 우리의 경우 NONCLUSTERED일부 테이블에 인덱스를 추가해야한다는 것을 깨달았습니다 .
zulucoda 2016 년

SQL 시간 초과 문제에 대한 MS 지원과 협력하고 있습니다. 이는 DB가 SQL Azure에서 호스팅되는 경우입니다. 모든 Azure PaaS 서비스 (PaaS 웹 사이트 및 SQL Azure 등)에 230 초의 유니버설 타임 아웃이 있으며 타임 아웃을 수동으로 설정 한 경우에도 항상 우선합니다. 이는 다중 테넌트 PaaS 인프라의 리소스를 보호하기위한 것입니다.
이안 로버트슨

답변:


552

EF 연결 문자열 내에 기본 명령 시간 초과를 지정하는 알려진 버그가 있습니다.

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

연결 문자열에서 값을 제거하고 데이터 컨텍스트 오브젝트 자체에 설정하십시오. 연결 문자열에서 충돌하는 값을 제거하면 작동합니다.

엔티티 프레임 워크 코어 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 버그를 찾을 수 없습니다.
rudimenter

7
나는 이것이 버그라고 생각하지는 않지만, 의도적으로 디자인 된 것입니다. 여기 비고 섹션 link
Mick P

3
일부 설정은 MS에 있고의 일부, 나는 그것을 보았다 때문에 여기에 , 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, 그래서 당신은 쉽게 다른 분으로 변경할 수 있습니다 :), 또한 컴파일러가 곱셈을 최적화하면 너무 놀라지 않을 것입니다!
Joel Verhagen

2
@JoelVerhagen, 놀라지 마십시오. 여기에 자동 최적화가 발생했을 때의 좋은 설명은 다음과 같습니다 stackoverflow.com/questions/160848/... . 이 경우, 심지어 두 가지 문자 값이기 때문에 발생한다고 가정하지만 솔직히 코드가 이상하다고 생각합니다.
Erick Petrucelli

33
meh ... 어린이들이 굶주리고 있습니다.
Timmerz

9
@ErikPetru, 이것은 실제로 매우 일반적인 관행이며 코드를 더 읽기 쉽게 만듭니다.
Calvin

DbContext파생 클래스가 edmx파일 에서 자동으로 생성 된 경우 이를 처리하는 가장 좋은 방법은 무엇입니까 ?
Matt Burland

41

DbContextEF 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 사용


전혀 좋은 접근 방식이 아닙니다. 나는 많은 거래 범위를 추가하고 프로젝트에서 나에게 악몽이되었습니다. 결국 EF 6+에서 모든 트랜잭션 범위를 단일 SAVEChanges ()로 대체했습니다. 이 coderwall.com/p/jnniww/…를
Moons

이 답변은 더 높은 투표율을 가져야합니다. 시간 제한을 늘리기 위해 모든 다른 방법을 시도했지만 컨텍스트 명령 시간 제한과 트랜잭션 범위를 모두 설정 한 경우에만 작동했습니다.

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

1

이것이 내가 투자 한 것입니다. 어쩌면 누군가에게 도움이 될 것입니다.

그래서 우리는 간다 :

EF와 함께 LINQ를 사용하면 다음과 같이 목록에 포함 된 정확한 요소를 찾습니다.

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

IdList에 둘 이상의 ID가 포함될 때까지 모든 것이 올바르게 진행됩니다.

목록에 ID가 하나만 있으면 "시간 초과"문제가 발생합니다. 이 문제를 해결하려면 if 조건을 사용하여 IdList에서 ID 수를 확인하십시오.

예:

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를 사용하고 Entity frameeork에서 생성 한 Select 문을 확인하십시오. …

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.