Pertanyaan Bagaimana cara mengidentifikasi fungsi-fungsi Linq yang tidak akan dipanggil ke sql beberapa kali?


            var costCenters = from c in dbContext.CostCenters //no sql call here
                          orderby c.DisplayRank descending
                          select c;


            List<CostCenter> lstCostCenter = costCenters.ToList();//Immediate execution to sql the first time

            lstCostCenter = costCenters.ToList();//no Sql call ??

            int test = costCenters.Count();//Call Sql everytime
            test = costCenters.Count();//Call Sql again???

Saya menggunakan Entity Framework 5

Saya mulai belajar Linq. Saya benar-benar bingung tentang fungsi eksekusi langsung yang akan dipanggil ke SQL setiap kali. Seperti yang Anda lihat pada contoh di atas, baik ToList () dan Count () adalah fungsi eksekusi langsung, tetapi hanya Count () yang akan terhubung ke sql pada panggilan subsequence. ToList () menghubungkan ke sql 1 kali, tetapi Count () akan terhubung ke Sql setiap kali.
Bagaimana cara mengidentifikasi fungsi linq mana yang tidak akan mendapat panggilan ke sql beberapa kali?


4
2018-01-09 15:24


asal


Jawaban:


Perbedaannya adalah pertama kali Anda memanggil ToList () itu mengkonversi IQueryable (yang hanya definisi dari sebuah query) ke daftar IEnumerable (query database). Dengan kata lain Anda mendapatkan kembali daftar objek yang sekarang dalam memori, sehingga panggilan LINQ lebih lanjut pada daftar yang dihasilkan menggunakan versi IEnumerable yang bekerja dengan objek-objek dalam memori. Selain itu EF memiliki fitur yang menyimpan hasil, sehingga bahkan jika Anda memanggil ToList pada referensi IQueryable asli, kemungkinan akan menggunakan objek di memori alih-alih mengambilnya dari database. saya menebak bahwa Hit menghitung database lagi daripada menghitung hasil yang di-cache, karena kueri untuk menghitung bukan kueri yang sama untuk ToList (ini adalah jenis agregat / pengelompokan), dan mungkin juga dirancang seperti itu karena mesin DB adalah lebih efisien dalam memberikan hitungan.

Dalam contoh Anda, costCenters adalah IQueryable, karena semua yang Anda lakukan adalah mendefinisikan permintaan, tetapi tidak memanggil ToList belum. lstCostCenter adalah IEnumerable yang mewakili hasil in-memory dari query setelah dieksekusi dengan ToList. Biasanya panggilan langsung yang menghasilkan hasil, .Count, .ToList, dll. Ketika dilakukan pada IQueryable akan menghasilkan panggilan DB (pengecualian ketika menemukan hasil cache yang dapat digunakan kembali), dan panggilan pada objek IEnumerable (dalam kasus Anda lstCostCenter) akan beroperasi di memori.

Untuk mendapatkan hasil yang lebih dapat diprediksi, panggillah ToList pada IQueryable terlebih dahulu, dan buat semua panggilan selanjutnya pada IEnumerable. Dengan kata lain, apa pun yang Anda minta lstCostCenter dijamin tidak akan memukul database. Ini biasanya cara terbaik untuk mengatasinya, kecuali jika Anda mengharapkan daftar yang dihasilkan menjadi besar. Misalnya, jika lstCostCenter berakhir dengan 10.000 objek, Anda mungkin tidak akan ingin melakukannya lstCostCenter.Where(x=>x.Blah > 5) karena itu akan melingkupi semua 10.000 objek dalam memori untuk menyaringnya. Dalam kasus seperti itu akan lebih baik untuk memodifikasi query pertama dengan menambahkan panggilan tambahan ke IQueryable dan kemudian memanggil ToList sehingga kita memanfaatkan mesin DB yang lebih baik dalam menangani set besar: costCenters.Where(x=>x.Blah > 5).ToList().


3
2018-01-09 16:03



Pertama-tama, ToList () tidak pernah menggunakan eksekusi yang ditangguhkan. Itu selalu mengaktualisasikan informasi dengan segera. Itu tidak terus kembali ke basis data setiap waktu karena sudah mengambil semua entitas.

Untuk mengetahui operator mana yang melakukan apa, lihat saja di tautan ini.


4
2018-01-09 15:31



http://msdn.microsoft.com/en-us/library/bb738633.aspx

Perbedaannya terletak pada "Paksa Eksekusi". Jika Anda memaksa segera mengeksekusi kueri, Anda menyimpan hasilnya. Dan operator konversi seperti ToList (), ToArray () dan bahkan foreach dikategorikan sebagai eksekusi kekuatan, sehingga panggilan lebih lanjut hanya akan beroperasi di dalam cache memori. Di mana sebagai Count (), First (), Max () dan Average () tidak dianggap sebagai eksekusi paksa ... Mereka adalah bagian dari permintaan ... Saya kira.


1
2018-01-09 16:31