Đã có một DataReader mở được liên kết với Lệnh này trước tiên phải được đóng lại


640

Tôi có truy vấn này và tôi nhận được lỗi trong chức năng này:

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

Lỗi là:

Đã có một DataReader mở được liên kết với Lệnh này trước tiên phải được đóng lại.

Cập nhật:

dấu vết ngăn xếp được thêm vào:

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

Câu trả lời:


1287

Điều này có thể xảy ra nếu bạn thực hiện một truy vấn trong khi lặp lại kết quả từ một truy vấn khác. Không rõ ràng từ ví dụ của bạn, nơi điều này xảy ra bởi vì ví dụ không đầy đủ.

Một điều có thể gây ra điều này là tải lười biếng được kích hoạt khi lặp qua kết quả của một số truy vấn.

Điều này có thể được giải quyết dễ dàng bằng cách cho phép MARS trong chuỗi kết nối của bạn. Thêm MultipleActiveResultSets=truevào phần nhà cung cấp của chuỗi kết nối của bạn (nơi Nguồn dữ liệu, Danh mục ban đầu, v.v.) được chỉ định).


34
Điều này làm việc cho tôi. Nếu bạn muốn đọc thêm về Kích hoạt nhiều bộ kết quả hoạt động (MARS), hãy xem msdn.microsoft.com/en-us/l Library / h32h3abf (v = vs.100) .aspx . Cân nhắc đọc lên những bất lợi của MARS quá stackoverflow.com/questions/374444/NH
Diganta Kumar

3
Tính đến hiệu suất, bạn cũng có thể giải quyết vấn đề này bằng cách bao gồm System.Data.Entity và sau đó sử dụng các câu lệnh Bao gồm để đảm bảo dữ liệu thứ cấp này được tải trong truy vấn ban đầu. Nếu bạn bật MARS, tắt nó đi để kiểm tra các tải dữ liệu lặp lại này có thể giúp tăng tốc các cuộc gọi xử lý dữ liệu của bạn bằng cách giảm các chuyến đi khứ hồi.
Chris Moschini

70
Việc kích hoạt MARS chỉ nên được thực hiện đối với một tập hợp nhỏ các vấn đề / trường hợp sử dụng. Trong hầu hết các trường hợp, lỗi trong câu hỏi là do BAD CODE gây ra trong ứng dụng gọi điện. Thêm chi tiết tại đây: devproconnections.com/development/
Michael

132
Thêm .ToList () sau your.Include (). Where () có thể sẽ giải quyết vấn đề.
Serj Sagan

2
Để thực hiện thay đổi rộng rãi kết nối SQL cho một truy vấn là vô lý. Câu trả lời đúng phải là ToList bên dưới. Một sửa chữa cục bộ (tức là chỉ thay đổi truy vấn) cho một vấn đề cục bộ!
bytedev

218

Bạn có thể sử dụng ToList()phương thức trước returncâu lệnh.

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
Tôi đã có lỗi này rất nhiều lần ... và mỗi lần tôi quên! Câu trả lời cho câu hỏi là luôn sử dụng ToList ().
Bánh mì nướng phô mai 21/07/2015

1
Có bất kỳ nhược điểm này? Nếu bạn có hàng 100k tôi nghi ngờ điều này có thể tốt.
Martin Dawson

2
@MartinMazzaDawson, Bạn thực sự cần 100 nghìn bản ghi cùng một lúc thực hiện truy vấn ?? Tôi nghĩ rằng, sử dụng phân trang là một ý tưởng tốt cho tình huống này
kazem

xin lỗi vì đã đưa ra một chủ đề cũ nhưng tôi đã gặp phải lỗi tương tự trong khi phát triển Rep StoragePotype và tôi đã giải quyết nó bằng cách thêm ".ToList () hoặc Single () hoặc Count ()" vào mọi phương thức của Kho lưu trữ. Trong khi ban đầu, tôi chỉ trở lại ".AsEnumerable ()". Bây giờ câu hỏi của tôi là: kho lưu trữ có trả về "ToList ()" hay đây là thứ gì đó sẽ được yêu cầu cho người tiêu dùng cuối cùng (ví dụ: logic dịch vụ / kinh doanh)
alessalessio

Làm việc cho tôi. Thêm .ToList sẽ giải quyết vấn đề về vấn đề hỗ trợ thập phân trong JetEntityFrameworkProvider. Total = storeDb.OF_Carts.Where(x => x.CartId == ShoppingCartId).ToList().Sum(t => t.Quantity * t.Item.UnitPrice);
hubert17

39

sử dụng cú pháp .ToList()để chuyển đổi đối tượng đọc từ db sang danh sách để tránh bị đọc lại. Hy vọng điều này sẽ làm việc với nó. Cảm ơn.


22

Đây là một chuỗi kết nối làm việc cho một người cần tham khảo.

  <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
Kích hoạt MARS là một cách giải quyết, KHÔNG phải là giải pháp cho vấn đề.
SandRock

5
Từ trang Tài liệu MARS: "Các hoạt động MARS không an toàn cho chuỗi." Điều đó có nghĩa là, nếu vấn đề phát sinh từ nhiều luồng truy cập vào Ngữ cảnh, MARS (có lẽ) không phải là giải pháp.
soái ca

20

Trong trường hợp của tôi, việc sử dụng đã Include()giải quyết lỗi này và tùy thuộc vào tình huống có thể hiệu quả hơn rất nhiều sau đó đưa ra nhiều truy vấn khi tất cả có thể được truy vấn cùng một lúc với một phép nối.

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

Đây là giải pháp tốt nhất nếu ứng dụng của bạn không yêu cầu MARS.
Fred Wilson

7

Tôi không biết liệu đây có phải là câu trả lời trùng lặp hay không. Nếu đó là tôi xin lỗi. Tôi chỉ muốn cho người nghèo biết cách tôi giải quyết vấn đề của mình bằng ToList ().

Trong trường hợp của tôi, tôi đã có ngoại lệ tương tự cho truy vấn dưới đây.

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

Tôi đã giải quyết như dưới đây

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

Có vẻ như bạn đang gọi DateLastUpdated từ trong một truy vấn đang hoạt động bằng cách sử dụng cùng bối cảnh EF và DateLastUpdate đưa ra lệnh cho chính kho lưu trữ dữ liệu. Entity Framework chỉ hỗ trợ một lệnh hoạt động cho mỗi bối cảnh.

Bạn có thể cấu trúc lại hai truy vấn trên thành một truy vấn như sau:

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

Tôi cũng nhận thấy bạn đang gọi các hàm như FormattedAccountNumber và FormattedRecordNumber trong các truy vấn. Trừ khi chúng được lưu trữ các procs hoặc các chức năng mà bạn đã nhập từ cơ sở dữ liệu của mình vào mô hình dữ liệu thực thể và được ánh xạ chính xác, chúng cũng sẽ đưa ra các ngoại lệ vì EF sẽ không biết cách dịch các hàm đó sang các câu lệnh mà nó có thể gửi đến kho lưu trữ dữ liệu.

Cũng lưu ý, việc gọi AsEnumerable không bắt buộc truy vấn phải thực thi. Cho đến khi thực hiện truy vấn được hoãn lại cho đến khi liệt kê. Bạn có thể buộc liệt kê với ToList hoặc ToArray nếu bạn muốn.


Nếu bạn muốn, bạn có thể cấu trúc lại truy vấn bạn đang thực hiện để nhận lệnh trực tiếp DateLastUpdated vào phép chiếu Chọn cho truy vấn Báo cáo tài khoản và nhận được hiệu ứng mong muốn mà không gặp lỗi.
James Alexander

Tôi đang gặp lỗi tương tự sau khi đặt mã hàm vào truy vấn chính
DotnetSparrow

2

Ngoài câu trả lời của Ladislav Mrnka :

Nếu bạn đang xuất bản và ghi đè vùng chứa trên tab Cài đặt , bạn có thể đặt NhiềuActiveResultSet thành True. Bạn có thể tìm thấy tùy chọn này bằng cách nhấp vào Nâng cao ... và nó sẽ nằm trong nhóm Nâng cao .


2

Đối với những người tìm thấy điều này thông qua Google;
Tôi đã gặp phải lỗi này vì, như được đề xuất bởi lỗi này, tôi đã không đóng SqlDataReader trước khi tạo một lỗi khác trên cùng một SqlCommand, vì cho rằng nó sẽ là rác được thu thập khi rời khỏi phương thức mà nó được tạo.

Tôi đã giải quyết vấn đề bằng cách gọi sqlDataReader.Close();trước khi tạo người đọc thứ hai.


2

Trong trường hợp của tôi, tôi đã mở một truy vấn từ ngữ cảnh dữ liệu, như

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

... và sau đó đã truy vấn tương tự ...

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

Thêm .ToListvào đầu tiên giải quyết vấn đề của tôi. Tôi nghĩ rằng nó có ý nghĩa để bọc này trong một tài sản như:

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

Trong đó _stores là một biến riêng tư và Bộ lọc cũng là một thuộc tính chỉ đọc từ AppSinstall.


1

Tôi đã có cùng một lỗi, khi tôi cố gắng cập nhật một số hồ sơ trong vòng lặp đọc. Tôi đã thử câu trả lời được bình chọn nhiều nhất MultipleActiveResultSets=truevà thấy rằng đó chỉ là cách giải quyết để nhận lỗi tiếp theo 

Giao dịch mới không được phép vì có các luồng khác đang chạy trong phiên

Cách tiếp cận tốt nhất, sẽ hiệu quả với các Kết quả lớn là sử dụng các đoạn và mở bối cảnh riêng cho từng đoạn như được mô tả trong  SqlException từ Entity Framework - Giao dịch mới không được phép vì có các luồng khác đang chạy trong phiên


1

Tôi đã giải quyết vấn đề này bằng cách thay đổi chờ đợi _accountSessionDataModel.SaveChangesAsync (); đến _accountSessionDataModel.SaveChanges (); trong lớp Kho lưu trữ của tôi.

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

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

Thay đổi nó thành:

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

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

Vấn đề là tôi đã cập nhật Phiên ở phía trước sau khi tạo phiên (bằng mã), nhưng vì SaveChangesAsync xảy ra không đồng bộ, việc tìm nạp các phiên gây ra lỗi này vì rõ ràng thao tác SaveChangesAsync chưa sẵn sàng.


1

Đối với tôi đó là lỗi của riêng tôi. Tôi đã cố gắng INSERTsử dụng SqlCommand.executeReader()khi tôi nên sử dụng SqlCommand.ExecuteNonQuery(). Nó đã được mở và không bao giờ đóng, gây ra lỗi. Xem ra cho sự giám sát này.


Đó là vấn đề tương tự từ phía tôi. Tôi cần SqlCommand.executeReader () vì tôi đang nhận ID hàng được chèn. Vì vậy: Tôi đã sử dụng SqlDataReader.C Đóng (); Lệnh Sql.Dispose (); Cảm ơn @Andrew Taylor
Fuat

1

Điều này được trích từ một kịch bản trong thế giới thực:

  • Mã hoạt động tốt trong môi trường Giai đoạn với NhiềuActiveResultSets được đặt trong chuỗi kết nối
  • Mã được xuất bản vào môi trường sản xuất mà không có nhiềuActiveResultSets = true
  • Vì vậy, nhiều trang / cuộc gọi hoạt động trong khi một trang bị lỗi
  • Nhìn gần hơn vào cuộc gọi, có một cuộc gọi không cần thiết được thực hiện với db và cần phải được loại bỏ
  • Đặt ManyActiveResultSets = true trong Sản xuất và xuất bản mã đã được dọn sạch, mọi thứ đều hoạt động tốt và hiệu quả

Tóm lại, không quên về MultActiveResultSets, mã có thể đã chạy trong một thời gian dài trước khi phát hiện ra một cuộc gọi db dự phòng có thể rất tốn kém và tôi khuyên bạn không nên hoàn toàn phụ thuộc vào việc đặt thuộc tính ManyActiveResultSets mà còn tìm hiểu tại sao mã cần nó nơi nó thất bại .


1

Nhiều khả năng sự cố này xảy ra do tính năng "tải chậm" của Entity Framework. Thông thường, trừ khi được yêu cầu rõ ràng trong quá trình tìm nạp ban đầu, tất cả dữ liệu đã tham gia (mọi thứ được lưu trữ trong các bảng cơ sở dữ liệu khác) chỉ được tìm nạp khi được yêu cầu. Trong nhiều trường hợp đó là một điều tốt, vì nó ngăn chặn việc tìm nạp dữ liệu không cần thiết và do đó cải thiện hiệu suất truy vấn (không tham gia) và tiết kiệm băng thông.

Trong tình huống được mô tả trong câu hỏi, quá trình tìm nạp ban đầu được thực hiện và trong giai đoạn "chọn" thiếu dữ liệu tải lười biếng được yêu cầu, các truy vấn bổ sung được đưa ra và sau đó EF phàn nàn về "mở DataReader".

Giải pháp được đề xuất trong câu trả lời được chấp nhận sẽ cho phép thực hiện các truy vấn này và thực sự toàn bộ yêu cầu sẽ thành công.

Tuy nhiên, nếu bạn sẽ kiểm tra các yêu cầu được gửi đến cơ sở dữ liệu, bạn sẽ nhận thấy nhiều yêu cầu - yêu cầu bổ sung cho mỗi dữ liệu bị thiếu (tải chậm). Đây có thể là một kẻ giết người hiệu suất.

Một cách tiếp cận tốt hơn là nói với EF để tải trước tất cả dữ liệu được tải lười biếng cần thiết trong truy vấn ban đầu. Điều này có thể được thực hiện bằng cách sử dụng câu lệnh "Bao gồm":

using System.Data.Entity;

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

Bằng cách này, tất cả các phép nối cần thiết sẽ được thực hiện và tất cả dữ liệu cần thiết sẽ được trả về dưới dạng một truy vấn duy nhất. Vấn đề được mô tả trong câu hỏi sẽ được giải quyết.


Đây là một câu trả lời hợp lệ, bởi vì tôi đã chuyển từ sử dụng Bao gồm sang sử dụng EntityEntry.Collection (). Load () và giải pháp của tôi đã chuyển từ làm việc sang bị hỏng. Thật không may, bao gồm cho một cái chung không thể "ThenInclude" một cái chung khác, vì vậy tôi vẫn đang cố gắng để EntityEntry.Collection (). Load () hoạt động.
AndrewBenjamin

0

Tôi đang sử dụng dịch vụ web trong công cụ của mình, nơi các dịch vụ đó tìm nạp thủ tục được lưu trữ. trong khi số lượng công cụ máy khách tìm nạp dịch vụ web nhiều hơn, vấn đề này phát sinh. Tôi đã sửa bằng cách chỉ định thuộc tính Đồng bộ hóa cho các hàm đó tìm nạp thủ tục được lưu trữ. Bây giờ nó đang hoạt động tốt, lỗi không bao giờ xuất hiện trong công cụ của tôi.

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

Thuộc tính này cho phép xử lý một yêu cầu tại một thời điểm. vì vậy điều này giải quyết vấn đề.


0

Như một lưu ý phụ ... điều này cũng có thể xảy ra khi có vấn đề với ánh xạ dữ liệu (nội bộ) từ các Đối tượng SQL.

Ví dụ...

Tôi đã tạo một SQL Scalar Functioncái mà vô tình trả lại một VARCHAR... và sau đó ... đã sử dụng nó để tạo một cột trong a VIEW. Bản đồ VIEWđã được ánh xạ chính xác trong DbContext... vì vậy Linq đã gọi nó là tốt. Tuy nhiên, thực thể dự kiến DateTime? VIEWđược trở về Chuỗi .

ODDLY nào ném ...

"Đã có một DataReader mở được liên kết với Lệnh này phải được đóng trước"

Thật khó để tìm ra ... nhưng sau khi tôi sửa các tham số trả về ... tất cả đều ổn


0

Trong trường hợp của tôi, tôi đã phải thiết lập MultipleActiveResultSetsđể Truetrong chuỗi kết nối.
Sau đó, nó xuất hiện một lỗi khác (lỗi thực tế) về việc không thể chạy 2 lệnh (SQL) cùng một lúc trên cùng một bối cảnh dữ liệu! (EF Core, Code trước)
Vì vậy, giải pháp cho tôi là tìm kiếm bất kỳ thực thi lệnh không đồng bộ nào khác và biến chúng thành đồng bộ , vì tôi chỉ có một DbContext cho cả hai lệnh.

Tôi hy vọng nó sẽ giúp bạn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.