Cara menggabungkan daftar dan daftar/tabel besar menggunakan LINQ

Awalnya saya punya daftar seperti ini:

List<Car> cars = db.Car.Where(x => x.ProductionYear == 2005).ToList();

Lalu saya mencoba menggabungkan daftar ini dengan dua tabel besar menggunakan LINQ seperti ini :

var joinedList = (from car in cars
                  join driver in db.Driver.ToList() 
                    on car.Id equals driver.CarId
                  join building in db.Building.ToList() 
                    on driver.BuildingId equals building.Id
                  select new Building
                  {
                     Name = building.Name;
                     Id = building.Id;
                     City = building.City;
                  }).ToList();

Tabel Driver dan Building memiliki sekitar 1 juta baris. Ketika saya menjalankan gabungan ini saya keluar dari pengecualian memori. Bagaimana saya bisa membuat bergabung ini berhasil? Haruskah saya melakukan operasi penggabungan di database? Jika ya, bagaimana saya bisa membawa daftar cars ke db? Terima kasih sebelumnya.


person jason    schedule 30.06.2017    source sumber
comment
db.Driver.ToList() Hapus ToList() dari ini, ini akan mencegah pengambilan seluruh tabel driver di memori. Demikian pula dari db.Building.   -  person Rahul Singh    schedule 30.06.2017
comment
@RahulSingh Saya melakukan itu, tetapi saya masih mendapatkan pengecualian.   -  person jason    schedule 30.06.2017
comment
apa rencanamu dengan koleksi ini?   -  person Gilad Green    schedule 30.06.2017
comment
Ya, itu tidak akan membantu jika gabungan Anda masih menghasilkan miliaran catatan. Anda harus memfilter dan mengambil data secara berkelompok (jika menampilkan data ini di UI atau semacamnya).   -  person Rahul Singh    schedule 30.06.2017
comment
@GiladGreen Saya mencoba mendapatkan gedung masing-masing untuk setiap mobil.   -  person jason    schedule 30.06.2017
comment
ya tapi lalu apa yang kamu rencanakan dengan itu   -  person Gilad Green    schedule 30.06.2017
comment
@GiladGreen Saya mencoba menampilkan informasi bangunan di situs web ASP.NET MVC.   -  person jason    schedule 30.06.2017
comment
@jason Berapa banyak hasil yang Anda dapatkan kembali? Ganti .ToList() terakhir dengan .Count() dan periksa.   -  person Zein Makki    schedule 30.06.2017
comment
@ user3185569 Bervariasi. Kadang beberapa puluh kadang beberapa ribu.   -  person jason    schedule 30.06.2017
comment
coba stackoverflow.com/a/11978832/5621827 ini atau gunakan beberapa filter atau paging saat mengambil catatan, saya rasa tidak ui akan membutuhkan begitu banyak rekaman sekaligus   -  person jitender    schedule 30.06.2017
comment
@jason Berapa banyak catatan yang Anda miliki di tabel mobil, gedung, dan pengemudi?   -  person Zein Makki    schedule 30.06.2017


Jawaban (3)


bahkan jika Anda telah menghapus .ToList() ganti dengan .AsQueryable()

AsQueryable Lebih Cepat dari ToList Dan AsEnumerable masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

  • Jika Anda membuat IQueryable, maka kueri dapat dikonversi ke sql dan dijalankan di server database

  • Jika Anda membuat IEnumerable, maka semua baris akan ditarik ke
    memori sebagai objek sebelum menjalankan kueri.

  • Dalam kedua kasus tersebut jika Anda tidak memanggil ToList() atau ToArray() maka kueri
    akan dieksekusi setiap kali digunakan, jadi, katakanlah, Anda memiliki
    IQueryable dan Anda mengisi 4 kotak daftar darinya , maka query akan dijalankan terhadap database sebanyak 4 kali.

jadi berikut kueri Linq yang Digunakan

var joinedList = (from car in db.Car.Where(x => x.ProductionYear == 2005).AsQueryable()
              join driver in db.Driver.AsQueryable() 
                on car.Id equals driver.CarId
              join building in db.Building.AsQueryable() 
                on driver.BuildingId equals building.Id
              select new Building
              {
                 Name = building.Name,
                 Id = building.Id,
                 City = building.City,
              }).ToList();
person kari kalan    schedule 30.06.2017
comment
Apa perbedaan antara db.Driver dan db.Driver.AsQueryable ? - person Zein Makki; 30.06.2017

Bahkan jika Anda menghapus panggilan .ToList() di dalam gabungan Anda, kode Anda akan tetap menarik semua data dan melakukan penggabungan di dalam memori dan bukan di server SQL. Ini karena Anda menggunakan daftar lokal cars di gabungan Anda. Di bawah ini akan menyelesaikan masalah Anda:

var joinedList = (from car in db.Car.Where(x => x.ProductionYear == 2005)
                  join driver in db.Driver 
                    on car.Id equals driver.CarId
                  join building in db.Building 
                    on driver.BuildingId equals building.Id
                  select new Building
                  {
                     Name = building.Name;
                     Id = building.Id;
                     City = building.City;
                  }).ToList();

Anda dapat menghapus .ToList() terakhir dan melakukan beberapa paging jika Anda berharap mendapatkan terlalu banyak record dalam hasil.

person Zein Makki    schedule 30.06.2017
comment
Sekarang menggunakan lebih sedikit memori tetapi masih mengkonsumsi lebih dari 1 GB memori. Apakah tidak ada cara untuk menguranginya? Dan apakah ada cara untuk mengosongkan memori setelah saya selesai bergabung? Terima kasih atas jawabannya. - person jason; 30.06.2017
comment
@jason joinedList harus menjadi segalanya yang perlu Anda khawatirkan setelah kode di atas dijalankan. Segala sesuatu yang tidak digunakan lagi ditandai untuk pengumpulan sampah (dan akan dikumpulkan suatu saat nanti ketika GC dipecat). Namun, jika joinedList memiliki terlalu banyak item, periksa baris terakhir dalam jawaban saya dan terapkan paging. - person Zein Makki; 30.06.2017
comment
Dalam satu kasus, saya mendapat pengecualian kehabisan memori dalam penggabungan itu. Saya melakukan persis seperti yang telah Anda lakukan. - person jason; 30.06.2017
comment
@jason Jawaban di atas memecahkan masalah di mana db.Driver, db.Building dan db.Card memiliki terlalu banyak catatan dan Anda menariknya ke dalam memori karena Anda melakukan join dengan cara yang salah. Namun jika hasil yang dikembalikan adalah daftar besar yang tidak sesuai ke dalam memori, maka paging adalah solusi untuk itu. Ingat, select new Building sedang membuat objek di memori, jika Anda memiliki terlalu banyak (Saya kira lebih dari 2 GB, Anda akan mendapatkan pengecualian kehabisan memori) Paging menyelesaikannya dengan membuat bagian objek sesuai permintaan. - person Zein Makki; 30.06.2017
comment
Saya tidak tahu mengapa tetapi ketika saya menambahkan AsQueryable() setelah tabel, itu bekerja dengan sangat efisien. - person jason; 30.06.2017
comment
@jason Ini tidak masuk akal bagi saya, db.Driver sudah merupakan turunan IQueryable dan metode itu hanya melakukan casting jika berlaku. Pasti ada faktor lain yang memengaruhi pengujian eksekusi Anda. - person Zein Makki; 30.06.2017

Pertama jangan pernah mencoba ToList() saat menggunakan LINQ (Anda bisa) tetapi pastikan Anda menggunakan ToList() sesedikit mungkin dalam skenario yang sangat jarang saja. Setiap kali Anda akan mendapatkan OutOfMemoryException ketika tabel berisi banyak baris. Jadi, inilah kode untuk pertanyaan Anda:

var joinedList = (from car in db.Car.GetQueryable().Where(x => x.ProductionYear == 2005)
              join driver in db.Driver.GetQueryable() on car.Id equals driver.CarId
              join building in db.Building.GetQueryable() on driver.BuildingId equals building.Id
              select new Building
              {
                 Name = building.Name;
                 Id = building.Id;
                 City = building.City;
              }).ToList();
person Starlord Live    schedule 30.06.2017
comment
dalam skenario yang sangat jarang .. Ini salah. Anda dapat melakukan beberapa enumerasi jika mengikuti saran ini yang memengaruhi kinerja dan melakukan perjalanan bolak-balik. Saran yang bagus adalah memahami eksekusi yang ditangguhkan, sehingga Anda dapat mengetahui kapan harus menggunakan .ToList() dan kapan tidak. - person Zein Makki; 30.06.2017
comment
Ya, saya setuju dengan Anda, jika Anda pembuat kode yang baik maka Anda akan tahu kapan harus menggunakan dan di mana menggunakan sesuai kebutuhan Anda setelah memahami eksekusi. Terkadang ini membantu berdasarkan logika bisnis. - person Starlord Live; 30.06.2017