Saya menggunakan Entity Framework dan kadang-kadang saya akan mendapatkan kesalahan ini.
EntityCommandExecutionException
{"There is already an open DataReader associated with this Command which must be closed first."}
at System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands...
Meskipun saya tidak melakukan manajemen koneksi manual.
kesalahan ini terjadi sesekali.
kode yang memicu kesalahan (disingkat agar mudah dibaca):
if (critera.FromDate > x) {
t= _tEntitites.T.Where(predicate).ToList();
}
else {
t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
}
menggunakan pola Buang untuk membuka koneksi baru setiap kali.
using (_tEntitites = new TEntities(GetEntityConnection())) {
if (critera.FromDate > x) {
t= _tEntitites.T.Where(predicate).ToList();
}
else {
t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
}
}
masih bermasalah
mengapa EF tidak akan menggunakan kembali koneksi jika sudah terbuka.
linq
entity-framework
sql-server-2008
Jiwa Sonic
sumber
sumber
predicate
danhistoricPredicate
variabel Anda. Saya telah menemukan bahwa jika Anda lulusFunc<T, bool>
untukWhere()
itu akan mengkompilasi dan kadang-kadang bekerja (karena melakukan "di mana" dalam memori). Apa yang Anda harus lakukan adalah lewatExpression<Func<T, bool>>
untukWhere()
.Jawaban:
Ini bukan tentang menutup koneksi. EF mengelola koneksi dengan benar. Pemahaman saya tentang masalah ini adalah bahwa ada beberapa perintah pengambilan data yang dieksekusi pada koneksi tunggal (atau perintah tunggal dengan banyak pilihan) sementara DataReader berikutnya dieksekusi sebelum yang pertama menyelesaikan pembacaan. Satu-satunya cara untuk menghindari pengecualian adalah untuk memungkinkan multiple DataReaders bersarang = nyalakan MultipleActiveResultSets. Skenario lain ketika ini selalu terjadi adalah ketika Anda beralih melalui hasil kueri (IQueryable) dan Anda akan memicu pemuatan malas untuk entitas yang dimuat di dalam iterasi.
sumber
Atau dengan menggunakan MARS (MultipleActiveResultSets) Anda dapat menulis kode Anda sehingga Anda tidak membuka beberapa set hasil.
Yang dapat Anda lakukan adalah mengambil data ke memori, sehingga pembaca tidak akan terbuka. Ini sering disebabkan oleh iterasi melalui resultset ketika mencoba untuk membuka set hasil lainnya.
Kode sampel:
Katakanlah Anda sedang melakukan pencarian di database Anda yang berisi ini:
Kita dapat melakukan solusi sederhana untuk ini dengan menambahkan .ToList () seperti ini:
Ini memaksa entitas untuk memuat daftar ke dalam memori, jadi ketika kita mengulanginya meskipun dalam loop foreach itu tidak lagi menggunakan pembaca data untuk membuka daftar, itu malah dalam memori.
Saya menyadari bahwa ini mungkin tidak diinginkan jika Anda ingin malas memuat beberapa properti misalnya. Ini sebagian besar adalah contoh yang diharapkan menjelaskan bagaimana / mengapa Anda mungkin mendapatkan masalah ini, sehingga Anda dapat membuat keputusan yang sesuai
sumber
ToList
memasukkan ribuan objek, itu akan menambah memori satu ton. Dalam contoh khusus ini, Anda sebaiknya menggabungkan permintaan dalam dengan yang pertama sehingga hanya satu permintaan yang dihasilkan daripada dua.Ada cara lain untuk mengatasi masalah ini. Apakah itu cara yang lebih baik tergantung pada situasi Anda.
Masalahnya adalah hasil dari pemuatan malas, jadi salah satu cara untuk menghindarinya adalah tidak memiliki pemuatan malas, melalui penggunaan Sertakan:
Jika Anda menggunakan yang sesuai
Include
, Anda dapat menghindari mengaktifkan MARS. Tetapi jika Anda melewatkannya, Anda akan mendapatkan kesalahan, jadi mengaktifkan MARS mungkin adalah cara termudah untuk memperbaikinya.sumber
.Include
adalah solusi yang jauh lebih baik daripada mengaktifkan MARS, dan jauh lebih mudah daripada menulis kode kueri SQL Anda sendiri.Anda mendapatkan kesalahan ini, ketika koleksi yang Anda coba untuk beralih adalah jenis pemuatan malas (IQueriable).
Mengubah koleksi IQueriable menjadi koleksi enumerable lainnya akan menyelesaikan masalah ini. contoh
Catatan: .ToList () membuat set baru setiap waktu dan itu dapat menyebabkan masalah kinerja jika Anda berurusan dengan data besar.
sumber
SELECT COUNT(*) FROM Users
= 5Saya memecahkan masalah dengan mudah (pragmatis) dengan menambahkan opsi ke konstruktor. Jadi, saya menggunakannya hanya saat dibutuhkan.
sumber
Coba di string koneksi Anda untuk mengatur
MultipleActiveResultSets=true
. Ini memungkinkan multitasking pada basis data.Itu berfungsi untuk saya ... apakah koneksi Anda di app.config atau Anda mengaturnya secara terprogram ... semoga ini membantu
sumber
Saya awalnya memutuskan untuk menggunakan bidang statis di kelas API saya untuk referensi contoh objek MyDataContext (Di mana MyDataContext adalah objek Konteks EF5), tetapi itulah yang tampaknya menciptakan masalah. Saya menambahkan kode seperti berikut ke setiap metode API saya dan itu memperbaiki masalahnya.
Seperti yang dinyatakan orang lain, objek Konteks Data EF TIDAK thread aman. Jadi menempatkan mereka di objek statis pada akhirnya akan menyebabkan kesalahan "pembaca data" di bawah kondisi yang tepat.
Asumsi awal saya adalah bahwa membuat hanya satu instance objek akan lebih efisien, dan memberikan manajemen memori yang lebih baik. Dari apa yang saya kumpulkan meneliti masalah ini, bukan itu masalahnya. Bahkan, tampaknya lebih efisien untuk memperlakukan setiap panggilan ke API Anda sebagai peristiwa aman yang terisolasi. Memastikan bahwa semua sumber daya dirilis dengan benar, karena objek keluar dari ruang lingkup.
Ini masuk akal terutama jika Anda membawa API Anda ke perkembangan alami berikutnya yang akan mengeksposnya sebagai WebService atau REST API.
Penyingkapan
sumber
Saya perhatikan bahwa kesalahan ini terjadi ketika saya mengirim IQueriable ke tampilan dan menggunakannya dalam double foreach, di mana foreach bagian dalam juga perlu menggunakan koneksi. Contoh sederhana (ViewBag.parents dapat IQueriable atau DbSet):
Solusi sederhana adalah untuk digunakan
.ToList()
pada koleksi sebelum menggunakannya. Perhatikan juga bahwa MARS tidak berfungsi dengan MySQL.sumber
ToList()
panggilan pertama untuk mendapatkan koleksi dari DB. Kemudian saya melakukanforeach
pada daftar itu dan panggilan berikutnya berfungsi dengan baik alih-alih memberikan kesalahan.Saya menemukan bahwa saya memiliki kesalahan yang sama, dan itu terjadi ketika saya menggunakan
Func<TEntity, bool>
bukanExpression<Func<TEntity, bool>>
untuk Andapredicate
.Setelah saya berubah semua
Func's
untukExpression's
pengecualian berhenti yang dilemparkan.Saya percaya bahwa
EntityFramwork
melakukan beberapa hal pintarExpression's
yang tidak ada hubungannya dengan ituFunc's
sumber
(MyTParent model, Func<MyTChildren, bool> func)
sehingga ViewModels saya dapat menentukanwhere
klausa tertentu untuk metode Generic DataContext. Tidak ada yang berhasil sampai saya melakukan ini.2 solusi untuk mengatasi masalah ini:
.ToList()
setelah kueri Anda, sehingga Anda kemudian dapat mengulanginya dengan membuka DataReader baru..Include
(/ entitas tambahan yang ingin Anda muat dalam query /) ini disebut eager loading, yang memungkinkan Anda untuk (memang) memasukkan objek terkait (entitas) selama ia mengeksekusi query dengan DataReader.sumber
Jalan tengah yang baik antara mengaktifkan MARS dan mengambil seluruh hasil yang diatur ke dalam memori adalah untuk mengambil hanya ID di kueri awal, dan kemudian loop melalui ID mematerialisasi setiap entitas saat Anda pergi.
Misalnya (menggunakan entitas sampel "Blog dan Posting" seperti dalam jawaban ini ):
Melakukan ini berarti Anda hanya menarik beberapa ribu bilangan bulat ke dalam memori, berbeda dengan ribuan keseluruhan grafik objek, yang seharusnya meminimalkan penggunaan memori sambil memungkinkan Anda untuk mengerjakan item-per-item tanpa mengaktifkan MARS.
Manfaat lain yang bagus dari ini, seperti yang terlihat dalam sampel, adalah Anda dapat menyimpan perubahan saat Anda mengulangi setiap item, daripada harus menunggu sampai akhir loop (atau solusi lain seperti itu), seperti yang akan diperlukan bahkan dengan MARS diaktifkan (lihat di sini dan di sini ).
sumber
context.SaveChanges();
inside loop :(. Ini tidak bagus. Itu pasti di luar loop.Dalam kasus saya, saya menemukan bahwa ada pernyataan "menunggu" yang hilang sebelum panggilan myContext.SaveChangesAsync (). Menambahkan menunggu sebelum panggilan async itu memperbaiki masalah pembaca data untuk saya.
sumber
Jika kita mencoba mengelompokkan sebagian kondisi kita menjadi Fungsi <> atau metode ekstensi, kita akan mendapatkan kesalahan ini, misalkan kita memiliki kode seperti ini:
Ini akan membuang pengecualian jika kita mencoba menggunakannya di Where (), yang harus kita lakukan adalah membangun Predikat seperti ini:
Selanjutnya dapat dibaca di: http://www.albahari.com/nutshell/predicatebuilder.aspx
sumber
Masalah ini dapat diatasi hanya dengan mengubah data menjadi daftar
sumber
Dalam situasi saya masalah terjadi karena registrasi injeksi ketergantungan. Saya menyuntikkan layanan per permintaan lingkup yang menggunakan dbcontext ke layanan tunggal terdaftar. Karenanya dbcontext digunakan dalam banyak permintaan dan karenanya kesalahan.
sumber
Dalam kasus saya masalah ini tidak ada hubungannya dengan string koneksi MARS tetapi dengan serialisasi json. Setelah memutakhirkan proyek saya dari NetCore2 ke 3 saya mendapatkan kesalahan ini.
Informasi lebih lanjut dapat ditemukan di sini
sumber
Saya memecahkan masalah ini menggunakan bagian kode berikut sebelum permintaan kedua:
Anda dapat mengubah waktu tidur dalam milidetik
PD Berguna saat menggunakan utas
sumber