이 명령과 관련된 열린 DataReader가 이미 있으며 먼저 닫아야합니다.


640

이 쿼리가 있고이 함수에서 오류가 발생합니다.

var accounts = from account in context.Accounts
               from guranteer in account.Gurantors
               select new AccountsReport
               {
                   CreditRegistryId = account.CreditRegistryId,
                   AccountNumber = account.AccountNo,
                   DateOpened = account.DateOpened,
               };

 return accounts.AsEnumerable()
                .Select((account, index) => new AccountsReport()
                    {
                        RecordNumber = FormattedRowNumber(account, index + 1),
                        CreditRegistryId = account.CreditRegistryId,
                        DateLastUpdated = DateLastUpdated(account.CreditRegistryId, account.AccountNumber),
                        AccountNumber = FormattedAccountNumber(account.AccountType, account.AccountNumber)
                    })
                .OrderBy(c=>c.FormattedRecordNumber)
                .ThenByDescending(c => c.StateChangeDate);


public DateTime DateLastUpdated(long creditorRegistryId, string accountNo)
{
    return (from h in context.AccountHistory
            where h.CreditorRegistryId == creditorRegistryId && h.AccountNo == accountNo
            select h.LastUpdated).Max();
}

오류는

이 명령과 관련된 열린 DataReader가 이미 있으며 먼저 닫아야합니다.

최신 정보:

스택 추적이 추가되었습니다.

InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.]
   System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command) +5008639
   System.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(String method, SqlCommand command) +23
   System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async) +144
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) +87
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +32
   System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +141
   System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) +12
   System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) +10
   System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) +443

[EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details.]
   System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) +479
   System.Data.Objects.Internal.ObjectQueryExecutionPlan.Execute(ObjectContext context, ObjectParameterCollection parameterValues) +683
   System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption) +119
   System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() +38
   System.Linq.Enumerable.Single(IEnumerable`1 source) +114
   System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__3(IEnumerable`1 sequence) +4
   System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle(IEnumerable`1 query, Expression queryRoot) +29
   System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute(Expression expression) +91
   System.Data.Entity.Internal.Linq.DbQueryProvider.Execute(Expression expression) +69
   System.Linq.Queryable.Max(IQueryable`1 source) +216
   CreditRegistry.Repositories.CreditRegistryRepository.DateLastUpdated(Int64 creditorRegistryId, String accountNo) in D:\Freelance Work\SuperExpert\CreditRegistry\CreditRegistry\Repositories\CreditRegistryRepository.cs:1497
   CreditRegistry.Repositories.CreditRegistryRepository.<AccountDetails>b__88(AccountsReport account, Int32 index) in D:\Freelance Work\SuperExpert\CreditRegistry\CreditRegistry\Repositories\CreditRegistryRepository.cs:1250
   System.Linq.<SelectIterator>d__7`2.MoveNext() +198
   System.Linq.Buffer`1..ctor(IEnumerable`1 source) +217
   System.Linq.<GetEnumerator>d__0.MoveNext() +96

답변:


1287

다른 쿼리의 결과를 반복하면서 쿼리를 실행하면 이런 일이 발생할 수 있습니다. 예제가 완료되지 않았기 때문에 이것이 어디서 발생하는지 명확하지 않습니다.

이를 유발할 수있는 한 가지는 일부 쿼리 결과를 반복 할 때 지연로드 트리거입니다.

연결 문자열에 MARS를 허용하면 쉽게 해결할 수 있습니다. MultipleActiveResultSets=true연결 문자열의 제공자 부분에 추가하십시오 (데이터 소스, 초기 카탈로그 등이 지정됨).


34
이것은 나를 위해 일했습니다. MARS (Multiple Active Result Set) 사용에 대한 자세한 내용은 msdn.microsoft.com/en-us/library/h32h3abf(v=vs.100).aspx를 참조 하십시오 . MARS의 단점도 읽어보십시오. stackoverflow.com/questions/374444/…
Diganta Kumar

3
성능을 고려하여 System.Data.Entity를 포함시킨 다음 Include 문을 사용하여이 보조 데이터가 원래 조회에로드되도록하여이를 해결할 수도 있습니다. MARS를 활성화 한 경우 반복되는 데이터로드를 확인하기 위해 MARS를 끄면 왕복을 줄여 데이터 처리 호출 속도를 높일 수 있습니다.
Chris Moschini

70
MARS 활성화는 문제 / 사용 사례의 매우 작은 하위 집합에 대해서만 수행해야합니다. 대부분의 경우, 해당 오류는 호출 응용 프로그램의 BAD CODE로 인해 발생합니다. 자세한 내용은 여기 : devproconnections.com/development/…
Michael K. Campbell

132
your.Include (). Where () 뒤에 .ToList ()를 추가하면 문제가 해결 될 것입니다.
Serj Sagan

2
하나의 쿼리에 대해 전역 SQL 연결을 광범위하게 변경하는 것은 어리 석습니다. 정답은 아래의 ToList 여야합니다. 지역화 된 문제에 대한 지역 수정 (즉, 쿼리 변경)!
bytedev

218

명령문 ToList()전에 메소드를 사용할 수 있습니다 return.

var accounts =
from account in context.Accounts
from guranteer in account.Gurantors

 select new AccountsReport
{
    CreditRegistryId = account.CreditRegistryId,
    AccountNumber = account.AccountNo,
    DateOpened = account.DateOpened,
};

 return accounts.AsEnumerable()
               .Select((account, index) => new AccountsReport()
                       {
                           RecordNumber = FormattedRowNumber(account, index + 1),
                           CreditRegistryId = account.CreditRegistryId,
                              DateLastUpdated = DateLastUpdated(account.CreditRegistryId, account.AccountNumber),
                           AccountNumber = FormattedAccountNumber(account.AccountType, account.AccountNumber)}).OrderBy(c=>c.FormattedRecordNumber).ThenByDescending(c => c.StateChangeDate).ToList();


 public DateTime DateLastUpdated(long creditorRegistryId, string accountNo)
    {
        var dateReported = (from h in context.AccountHistory
                            where h.CreditorRegistryId == creditorRegistryId && h.AccountNo == accountNo
                            select h.LastUpdated).Max();
        return dateReported;
    }

9
나는 지금이 오류를 여러 번 겪었습니다 ... 그리고 잊을 때마다! 질문에 대한 답변은 항상 ToList ()를 사용하는 것입니다.
Cheesus Toast

1
이것에 대한 단점이 있습니까? 100k 개의 행이 있다면 이것이 좋을지 의심됩니다.
Martin Dawson

2
@MartinMazzaDawson, 당신은 정말로 한 번의 쿼리 실행에 100K 레코드가 필요합니까 ?? 난 그렇게 생각, 페이지 매김을 사용하여이 상황에 대한 좋은 아이디어입니다
kazem

오래된 주제를 제기하여 죄송하지만 RepositoryPattern을 개발하는 동안 동일한 오류가 발생하여 Repository의 모든 메소드에 ".ToList () 또는 Single () 또는 Count ()"를 추가하여 문제를 해결했습니다. 처음에는 ".AsEnumerable ()"을 반환하고있었습니다. 이제 내 질문은 : 저장소가 "ToList ()"를 반환해야 하는가 아니면 최종 소비자 (예 : 서비스 / 비즈니스 로직)에게 요구되는 것
alessalessio

나를 위해 작동합니다. .ToList를 추가하면 JetEntityFrameworkProvider의 Decimal 지원 문제가 해결됩니다. Total = storeDb.OF_Carts.Where(x => x.CartId == ShoppingCartId).ToList().Sum(t => t.Quantity * t.Item.UnitPrice);
hubert17


22

다음은 참조가 필요한 사람을위한 작동중인 연결 문자열입니다.

  <connectionStrings>
    <add name="IdentityConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\IdentityDb.mdf;Integrated Security=True;MultipleActiveResultSets=true;" providerName="System.Data.SqlClient" />
  </connectionStrings>

15
MARS를 사용하면 문제에 대한 해결책이 아닌 해결 방법입니다.
SandRock

5
MARS Documentation 페이지에서 : "MARS 작업은 스레드로부터 안전하지 않습니다." 즉, 컨텍스트에 액세스하는 여러 스레드에서 문제가 발생하면 MARS가 해결책이 아닙니다.
마르 소프

20

필자의 Include()경우이 오류 를 해결하고 상황에 따라 조인으로 모든 쿼리를 한 번에 쿼리 할 수있을 때 여러 쿼리를 발행하는 것보다 훨씬 효율적일 수 있습니다.

IEnumerable<User> users = db.Users.Include("Projects.Tasks.Messages");

foreach (User user in users)
{
    Console.WriteLine(user.Name);
    foreach (Project project in user.Projects)
    {
        Console.WriteLine("\t"+project.Name);
        foreach (Task task in project.Tasks)
        {
            Console.WriteLine("\t\t" + task.Subject);
            foreach (Message message in task.Messages)
            {
                Console.WriteLine("\t\t\t" + message.Text);
            }
        }
    }
}

응용 프로그램에 MARS가 필요하지 않은 경우이 방법이 가장 좋습니다.
Fred Wilson

7

이것이 중복 답변인지 아닌지 모르겠습니다. 죄송 합니다만 ToList ()를 사용하여 문제를 해결하는 방법을 가난한 사람들에게 알리고 싶습니다.

내 경우에는 아래 쿼리에 대해 동일한 예외가 발생했습니다.

int id = adjustmentContext.InformationRequestOrderLinks.Where(item => item.OrderNumber == irOrderLinkVO.OrderNumber && item.InformationRequestId == irOrderLinkVO.InformationRequestId).Max(item => item.Id);

나는 아래와 같이 해결했다

List<Entities.InformationRequestOrderLink> links = adjustmentContext.InformationRequestOrderLinks
.Where(item => item.OrderNumber == irOrderLinkVO.OrderNumber && item.InformationRequestId == irOrderLinkVO.InformationRequestId).ToList();

int id = 0;

if (links.Any())
{
  id = links.Max(x => x.Id);
 }
if (id == 0)
{
//do something here
}

5

동일한 EF 컨텍스트를 사용하여 활성 쿼리 내에서 DateLastUpdated를 호출하고 DateLastUpdate가 데이터 저장소 자체에 명령을 실행하는 것으로 보입니다. Entity Framework는 한 번에 컨텍스트 당 하나의 활성 명령 만 지원합니다.

위의 두 쿼리를 다음과 같이 리팩토링 할 수 있습니다.

return accounts.AsEnumerable()
        .Select((account, index) => new AccountsReport()
        {
          RecordNumber = FormattedRowNumber(account, index + 1),
          CreditRegistryId = account.CreditRegistryId,
          DateLastUpdated = (
                                                from h in context.AccountHistory 
                                                where h.CreditorRegistryId == creditorRegistryId 
                              && h.AccountNo == accountNo 
                                                select h.LastUpdated).Max(),
          AccountNumber = FormattedAccountNumber(account.AccountType, account.AccountNumber)
        })
        .OrderBy(c=>c.FormattedRecordNumber)
        .ThenByDescending(c => c.StateChangeDate);

또한 쿼리에서 FormattedAccountNumber 및 FormattedRecordNumber와 같은 함수를 호출하는 것으로 나타났습니다. 데이터베이스에서 엔티티 데이터 모델로 가져온 proc 또는 함수가 저장되어 있고 올바르게 매핑되어 있지 않으면 EF는 해당 함수를 데이터 저장소로 보낼 수있는 명령문으로 변환하는 방법을 알지 못하므로 예외가 발생합니다.

또한 AsEnumerable을 호출해도 쿼리가 강제로 실행되지는 않습니다. 열거 될 때까지 쿼리 실행이 지연 될 때까지 원하는 경우 ToList 또는 ToArray를 사용하여 열거를 강제 할 수 있습니다.


원하는 경우 보고서를 리팩터링하여 DateLastUpdated를 직접 Accounts Report 쿼리의 Select 투영으로 가져오고 오류없이 원하는 효과를 얻을 수 있습니다.
James Alexander

메인 쿼리에 함수 코드를 넣은 후에도 같은 오류가 발생합니다
DotnetSparrow

2

Ladislav Mrnka의 답변 외에도 :

설정 탭에서 컨테이너를 게시하고 재정의하는 경우 MultipleActiveResultSet 을 True로 설정할 수 있습니다 . 고급 ... 을 클릭하여이 옵션을 찾을 수 있으며 고급 그룹 아래에 있습니다 .


2

구글을 통해 이것을 찾는 사람들을 위해;
오류에서 제안한 것처럼 동일한 SqlCommand에서 다른 것을 작성하기 전에 SqlDataReader를 닫지 못했기 때문에이 오류가 발생했습니다. 실제로 작성된 메소드를 떠날 때 가비지 수집된다고 가정합니다.

sqlDataReader.Close();두 번째 독자를 만들기 전에 전화로 문제를 해결했습니다 .


2

필자의 경우 데이터 컨텍스트에서 쿼리를 열었습니다.

    Dim stores = DataContext.Stores _
        .Where(Function(d) filter.Contains(d.code)) _

... 그리고 그 다음에 같은 것을 쿼리했습니다 ...

    Dim stores = DataContext.Stores _
        .Where(Function(d) filter.Contains(d.code)).ToList

를에 추가하면 .ToList내 문제가 해결되었습니다. 나는 이것을 다음과 같은 속성으로 감싸는 것이 합리적이라고 생각합니다.

Public ReadOnly Property Stores As List(Of Store)
    Get
        If _stores Is Nothing Then
            _stores = DataContext.Stores _
                .Where(Function(d) Filters.Contains(d.code)).ToList
        End If
        Return _stores
    End Get
End Property

여기서 _stores는 개인 변수이고 Filters는 AppSettings에서 읽는 읽기 전용 속성입니다.


1

읽기 루프 내에서 일부 레코드를 업데이트하려고 할 때 동일한 오류가 발생했습니다. 가장 투표가 많은 답변을 시도 MultipleActiveResultSets=true하고 다음 오류를 얻는 것이 해결 방법이라는 것을 알았습니다. 

세션에서 다른 스레드가 실행 중이므로 새 트랜잭션이 허용되지 않습니다.

거대한 ResultSet에 작동하는 가장 좋은 방법 은 Entity Framework의 SqlException에 설명 된대로 청크를 사용하고 각 청크에 대해 별도의 컨텍스트를 여는 것  입니다. 세션에서 실행중인 다른 스레드가 있으므로 새 트랜잭션이 허용되지 않습니다.


1

await _accountSessionDataModel.SaveChangesAsync ();를 변경하여이 문제를 해결했습니다. _accountSessionDataModel.SaveChanges (); 내 리포지토리 클래스에서.

 public async Task<Session> CreateSession()
    {
        var session = new Session();

        _accountSessionDataModel.Sessions.Add(session);
        await _accountSessionDataModel.SaveChangesAsync();
     }

그것을 다음과 같이 변경했습니다.

 public Session CreateSession()
    {
        var session = new Session();

        _accountSessionDataModel.Sessions.Add(session);
        _accountSessionDataModel.SaveChanges();
     }

문제는 세션에서 코드를 생성 한 후 프론트 엔드에서 세션을 업데이트했지만 SaveChangesAsync가 비동기 적으로 발생하기 때문에 세션을 가져 오면 분명히 SaveChangesAsync 작업이 아직 준비되지 않았기 때문에이 오류가 발생했습니다.


1

글쎄, 그것은 내 자신의 버그였습니다. INSERT사용 SqlCommand.executeReader()하고 있어야 할 때 사용 하려고했습니다 SqlCommand.ExecuteNonQuery(). 열리고 닫히지 않아 오류가 발생했습니다. 이 감독에주의하십시오.


내 입장에서도 같은 문제였습니다. Inserted rows ID를 받고 있기 때문에 SqlCommand.executeReader ()가 필요했습니다. 그래서 : 나는 SqlDataReader.Close ()를 사용했다. SQL Command.Dispose (); 감사합니다 @Andrew Taylor
Fuat

1

이것은 실제 시나리오에서 추출한 것입니다.

  • 연결 문자열에 MultipleActiveResultSets가 설정되어있는 스테이지 환경에서 코드가 잘 작동 함
  • MultipleActiveResultSets = true없이 프로덕션 환경에 게시 된 코드
  • 단일 페이지가 실패하는 동안 많은 페이지 / 호출이 작동합니다.
  • 전화를 자세히 보면 불필요한 전화가 있습니다 DB에 이 있으므로 제거해야합니다.
  • 프로덕션에서 MultipleActiveResultSets = true로 설정하고 정리 된 코드를 게시하면 모든 것이 효율적으로 작동합니다.

결론적으로 MultipleActiveResultSets를 잊어 버리지 않으면 서 비용이 많이 드는 중복 db 호출을 발견하기 전에 코드가 오랫동안 실행되었을 수 있으며 MultipleActiveResultSets 속성 설정에 전적으로 의존하지 않고 코드에 필요한 이유를 찾는 것이 좋습니다. 실패한 곳 .


1

이 문제는 대부분 Entity Framework의 "지연 로딩"기능으로 인해 발생합니다. 일반적으로 초기 페치 중에 명시 적으로 요구되지 않는 한 결합 된 모든 데이터 (다른 데이터베이스 테이블에 저장된 데이터)는 필요할 때만 페치됩니다. 많은 경우에 이는 불필요한 데이터를 가져 오지 못하도록하여 쿼리 성능을 향상 시키며 (조인 없음) 대역폭을 절약하기 때문에 좋은 일입니다.

질문에 설명 된 상황에서 초기 페치가 수행되고 "선택"단계 중에 누락 된 지연로드 데이터가 요청되고 추가 쿼리가 발행 된 후 EF가 "open DataReader"에 대해 불평합니다.

허용 된 답변에 제안 된 해결 방법은 이러한 쿼리를 실행할 수 있으며 실제로 전체 요청이 성공합니다.

그러나 데이터베이스로 전송 된 요청을 검사하면 누락 된 (지연된 각) 데이터에 대한 추가 요청 인 여러 요청이 표시됩니다. 성능이 저하 될 수 있습니다.

더 좋은 방법은 초기 쿼리 중에 필요한 모든 지연로드 된 데이터를 미리로드하도록 EF에 알리는 것입니다. "Include"문을 사용하여 수행 할 수 있습니다.

using System.Data.Entity;

query = query.Include(a => a.LazyLoadedProperty);

이렇게하면 필요한 모든 조인이 수행되고 필요한 모든 데이터가 단일 쿼리로 반환됩니다. 질문에 설명 된 문제가 해결됩니다.


이것은 Include를 사용하여 EntityEntry.Collection (). Load ()를 사용하기 시작했고 솔루션이 작동하지 않았기 때문에 올바른 대답입니다. 불행히도 제네릭을 포함하면 다른 제네릭을 "ThenInclude"할 수 없으므로 여전히 EntityEntry.Collection (). Load () 작동하도록 노력하고 있습니다.
AndrewBenjamin

0

내 도구에서 웹 서비스를 사용하고 있는데 해당 서비스에서 저장 프로 시저를 가져옵니다. 더 많은 수의 클라이언트 도구가 웹 서비스를 가져 오는 동안이 문제가 발생합니다. 해당 함수에 대해 동기화 속성을 지정하여 저장 프로 시저를 가져 와서 수정했습니다. 이제는 정상적으로 작동하지만 오류가 도구에 나타나지 않았습니다.

 [MethodImpl(MethodImplOptions.Synchronized)]
 public static List<t> MyDBFunction(string parameter1)
  {
  }

이 속성을 사용하면 한 번에 하나의 요청을 처리 할 수 ​​있습니다. 이렇게하면 문제가 해결됩니다.


0

부수적으로 ... 이것은 SQL 객체의 (내부) 데이터 매핑에 문제가있는 경우에도 발생할 수 있습니다.

예를 들어 ...

내가 만든 SQL Scalar Function실수 를 반환 VARCHAR... 다음 ... 그리고의 열을 생성하는 데 사용 VIEW. 이 VIEW올바르게에 매핑 된 DbContext... 그래서 Linq에이 잘 그것을 호출했다. 그러나 엔터티는 DateTime을 예상 했습니까? 그리고 VIEW반환 문자열 .

이상하게 던지는 ...

"먼저이 명령과 연관된 열린 DataReader가 열려 있어야합니다."

파악하기 어려웠지만 반환 매개 변수를 수정 한 후 ... 모두 잘되었습니다.


0

필자의 경우 연결 문자열에서 를 설정해야 MultipleActiveResultSets했습니다 True.
그런 다음 동일한 데이터 컨텍스트에서 2 (SQL) 명령을 동시에 실행할 수 없다는 또 다른 오류 (실제 오류)가 나타났습니다! (EF Core, Code first)
따라서 두 가지 명령에 대해 하나의 DbContext 만 있으므로 다른 비동기 명령 실행을 찾아서 동기식으로 돌리는 것이 해결책이었습니다.

도움이 되길 바랍니다

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