เหตุใดไฟฟ้าลัดวงจรนี้ไม่ทำงานในแบบสอบถาม linq ถึง sql

แบบสอบถาม:

List<int> companyIds = null;

(from car in context.GetTable<Car>()
where companyIds == null || companyIds.Contains(car.companyID)
select car)
.ToList();

ผลลัพธ์:

ที่ System.Linq.Enumerable.OfType[TResult] (แหล่ง IEnumerable) ที่ System.Data.Linq.SqlClient.QueryConverter.VisitContains (ลำดับนิพจน์ ค่านิพจน์) ที่ System.Data.Linq.SqlClient.QueryConverter.VisitInner (โหนดนิพจน์) ที่ System.Data.Linq.SqlClient.QueryConverter.VisitExpression (Expression exp) ที่ System.Data.Linq.SqlClient.QueryConverter.VisitBinary (BinaryExpression b) ที่ System.Data.Linq.SqlClient.QueryConverter.VisitInner (โหนด Expression) ที่ System .Data.Linq.SqlClient.QueryConverter.VisitExpression(Expression exp) ที่ System.Data.Linq.SqlClient.QueryConverter.VisitWhere(ลำดับนิพจน์, เพรดิเคต LambdaExpression) ที่ System.Data.Linq.SqlClient.QueryConverter.VisitInner(โหนด Expression) ที่ System.Data.Linq.SqlClient.QueryConverter.ConvertOuter (โหนดนิพจน์) ที่ System.Data.Linq.SqlClient.SqlProvider.BuildQuery (แบบสอบถามนิพจน์ คำอธิบายประกอบ SqlNodeAnnotations) ที่ System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq .Provider.IProvider.Execute(Expression query) ที่ System.Data.Linq.DataQuery1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) ที่ EVaultSDK.Services.CompanyService.Get...

ถ้าฉันเพิ่ม ToList

 context.GetTable<Car>().ToList()

มันได้ผล


person vborutenko    schedule 14.09.2018    source แหล่งที่มา
comment
โอเปอเรเตอร์เครื่องหมายคำถามใช้ได้ที่นี่หรือไม่   -  person Ctznkane525    schedule 14.09.2018
comment
@maccettura ไม่แน่ใจว่าฉันเห็นด้วยกับสิ่งนั้น รหัสที่นำเสนอข้างต้นนั้นถูกต้องตามหลักตรรกะ แม้ว่าจะไม่มี select ดังนั้นฉันจึงไม่แน่ใจว่ามันสมบูรณ์หรือไม่   -  person DavidG    schedule 14.09.2018
comment
@maccettura อ่านเรื่องไฟฟ้าลัดวงจร ถ้าข้อแรกเป็นจริง ไม่ต้องทำข้อสอง   -  person vborutenko    schedule 14.09.2018
comment
@cosset ดังนั้นคุณต้องการทุกบันทึกที่ companyIds เป็นโมฆะ และที่ companyIds มี x?   -  person maccettura    schedule 14.09.2018
comment
@DavidG คุณพูดถูกเพิ่มการเลือก   -  person vborutenko    schedule 14.09.2018
comment
@maccettura ฉันต้องการถ้า companyIds เป็นโมฆะ - ส่งคืนรถยนต์ทั้งหมดหากไม่ใช่ - ส่งคืนเฉพาะรถยนต์ที่มี companyId ที่เหมาะสมแน่นอนฉันทำ companyIds = null ก่อนแบบสอบถามเท่านั้น   -  person vborutenko    schedule 14.09.2018
comment
บริบทไม่เป็นโมฆะ companyIds เป็นโมฆะและ linq พยายามดำเนินการบรรจุด้วยค่าว่าง แต่ไม่ควรดำเนินการส่วนคำสั่งที่สองเนื่องจากส่วนแรกเป็นจริง   -  person vborutenko    schedule 14.09.2018
comment
@cosset คุณลองเพิ่ม ToList ที่นี่: context.GetTable<Car>().ToList() แล้วดูว่าคุณได้รับข้อยกเว้นอีกครั้งหรือไม่ และคุณสามารถโพสต์การติดตามสแต็กแบบเต็มของข้อยกเว้นได้หรือไม่   -  person Selman Genç    schedule 14.09.2018
comment
ใช่แล้ว สแต็กเทรซยืนยันความสงสัยของฉัน   -  person Selman Genç    schedule 14.09.2018
comment
@CetinBasoz ใช่คำตอบของคุณสามารถเรียกว่าวิธีแก้ปัญหาได้ แต่มันไม่ถูกต้องตามหลักตรรกะ ถ้าฉันส่งผ่านไปยังวิธีว่างเปล่า (ไม่ใช่ค่าว่าง) companyIds ฉันคาดว่าวิธีการจะไม่คืนอะไรเลยสำหรับ บริษัท puprpose นั้นสามารถเป็นโมฆะได้   -  person vborutenko    schedule 14.09.2018
comment
@cosset ตกลง ฉันจะแก้ไขโซลูชันเพื่อคุณโดยเฉพาะ   -  person Cetin Basoz    schedule 14.09.2018
comment
หากคุณเพิ่ม context.GetTable‹Car›().ToList() มันจะใช้งานไม่ได้จริงๆ ในกรณีนั้น คุณกำลังทำลายจุดประสงค์ของคุณและนำข้อมูลทั้งหมดมาไม่ว่าคุณจะมีสิ่งใดในการเลือกก็ตาม ด้วยข้อมูลขนาดเล็กมันจะไม่สามารถสังเกตเห็นได้ แต่ถ้าคุณมีข้อมูลขนาดใหญ่ระวังคุณจะดึงสายทั้งตารางทุกครั้ง   -  person Cetin Basoz    schedule 14.09.2018
comment
@CetinBasoz ใช่ฉันรู้เรื่องนี้   -  person vborutenko    schedule 14.09.2018


คำตอบ (2)


ฉันคิดว่าเหตุผลก็คือคุณใช้ LINQ เป็น SQL คำค้นหาของคุณจะต้องแปลเป็น SQL และคุณจะได้รับข้อยกเว้นในขณะที่การแปลนี้เกิดขึ้น Contains ถูกแปลเป็นตัวดำเนินการ IN ใน SQL แต่เนื่องจากรายการเป็นโมฆะ ฉันคิดว่าผู้ให้บริการ LINQ ถึง SQL จึงมีข้อยกเว้น

นี่คือเหตุผลที่คุณไม่ได้รับข้อยกเว้นเมื่อคุณเพิ่ม ToList หลัง GetTable<Car>() ซึ่งจะทำให้คุณดึงข้อมูลและโหลด Cars ทั้งหมดในหน่วยความจำ ดังนั้นแบบสอบถามจึงทำงานบนหน่วยความจำ ดังนั้นจึงไม่จำเป็นต้องแปลเป็น SQL และข้อความสั้น - วงจรทำงานได้ตามที่คาดไว้

โดยปกติถ้าคุณโทร Contains ในรายการว่าง คุณควรได้รับ NullReferenceException แต่คุณจะได้รับ ArgumentNullException ดังนั้น คุณควรตรวจสอบการติดตามสแต็ก และหากเป็นเช่นนั้น อย่าใช้รายการว่างในการสืบค้นของคุณ

แก้ไข: การติดตามสแต็กที่คุณโพสต์ยืนยันสมมติฐานของฉัน มีเรียกใช้เมธอด OfType ที่ไหนสักแห่งบนรายการ และทำให้เกิดข้อยกเว้น

person Selman Genç    schedule 14.09.2018

คุณได้รับคำตอบที่ดีอยู่แล้วว่าเหตุใดคุณจึงได้รับข้อผิดพลาด ไม่ใช่ทุกอย่างใน C# ที่แปลเป็น SQL ได้อย่างดี และคุณมักจะไม่ทราบคำตอบจนกว่าจะถึงรันไทม์

ในกรณีที่ผู้เยี่ยมชมในอนาคตพบคำถามนี้เพื่อค้นหาวิธีแก้ปัญหา ฉันขอแนะนำให้ใช้ข้อเท็จจริงที่ว่าคุณสามารถสร้างแบบสอบถามขึ้นมาได้ และจะไม่ดึงข้อมูลใด ๆ จนกว่าคุณจะโทร ToList() (หรือ Single() ฯลฯ...):

List<int> companyIds = null;

var query = context.GetTable<Car>();
if (companyIds != null)
    query = query.Where(car => companyIds.Contains(car.companyID));

var result = query.ToList();
person Grant Winney    schedule 14.09.2018
comment
เฮ้เตรียมพร้อมที่จะถูกโหวตให้เสนอวิธีแก้ปัญหาแทนที่จะตอบคำถามของเขา :) BTW คุณพลาด AsQueryable() - person Cetin Basoz; 14.09.2018