อะไรคือความแตกต่างระหว่าง null และ System.DBNull.Value?


92

มีความแตกต่างระหว่าง null และ System.DBNull.Value หรือไม่ ถ้าใช่มันคืออะไร?

ฉันสังเกตเห็นพฤติกรรมนี้แล้ว -

while (rdr.Read())
{
    if (rdr["Id"] != null) //if (rdr["Id"] != System.DBNull.Value)  
    {
        int x = Convert.ToInt32(rdr["Id"]);
    }
}

ในขณะที่ฉันดึงข้อมูลจากฐานข้อมูลโดยใช้ sql datareader แม้ว่าจะไม่มีค่าที่ส่งif(rdr["Id"] != null)คืนกลับมาtrueและในที่สุดก็มีข้อยกเว้นสำหรับการแคสต์ null เป็นจำนวนเต็ม

แต่นี้ถ้าผมใช้ผลตอบแทนif (rdr["Id"] != System.DBNull.Value)false

ความแตกต่างระหว่าง null และ System.DBNull.Value คืออะไร?


พวกเขาไม่เกี่ยวกัน หนึ่งเป็นอินสแตนซ์คงที่ของคลาสในSystem.Dataและอีกค่าหนึ่งเป็นค่าพิเศษที่บ่งบอกถึงการขาดการอ้างอิง พวกเขาไม่มีอะไรเกี่ยวข้องกัน คุณสามารถอธิบายสิ่งที่คุณสับสนอย่างละเอียดได้หรือไม่? คำถามที่แท้จริงของคุณคือ "ทำไมต้องทำDataRowsและDataReadersใส่ไว้DBNull.Valueในตัวเองแทนnull?
mqp

ตอนแรกของฉันไม่ใช่ แต่หลังจากเรียนรู้จากสิ่งที่คุณพูดฉันก็อยากรู้อยากเห็น คุณช่วยบอกฉันได้ไหมว่าทำไม DataRows และ DataReaders ใส่ DBNull.Value ในตัวเองแทนที่จะเป็น null
pavanred

ฉันไม่แน่ใจตัวเอง นี่คือคำตอบหนึ่งคำตอบ: stackoverflow.com/questions/4488727/what-is-the-point-of-dbnull/…นอกจากนี้ยังเป็นไปได้ว่าก่อนที่ประเภทค่าที่เป็นโมฆะจะอยู่รอบ ๆ C # การจัดการจะมีความยุ่งยากnullมากกว่านี้
mqp

1
ฉันมีคำตอบที่นี่ แต่ฉันรู้ว่ามันเหมาะสำหรับstackoverflow.com/questions/4488727/what-is-the-point-of-dbnull - ดังนั้นฉันจึงย้ายมัน
Marc Gravell

คำตอบ:


118

ดีnullไม่ได้เป็นตัวอย่างของชนิดใด ๆ แต่เป็นการอ้างอิงที่ไม่ถูกต้อง

อย่างไรก็ตามSystem.DbNull.Valueเป็นการอ้างอิงที่ถูกต้องไปยังอินสแตนซ์ของSystem.DbNull( System.DbNullเป็นซิงเกิลตันและSystem.DbNull.Valueให้การอ้างอิงถึงอินสแตนซ์เดียวของคลาสนั้น) ซึ่งแสดงถึงค่า* ที่ไม่มีอยู่ในฐานข้อมูล

* ปกติเราจะพูดnullแต่ฉันไม่ต้องการทำให้ปัญหาสับสน

ดังนั้นจึงมีความแตกต่างทางแนวคิดอย่างมากระหว่างทั้งสอง คำหลักnullแสดงถึงข้อมูลอ้างอิงที่ไม่ถูกต้อง คลาสSystem.DbNullแสดงค่าที่ไม่มีอยู่ในฟิลด์ฐานข้อมูล โดยทั่วไปเราควรพยายามหลีกเลี่ยงการใช้สิ่งเดียวกัน (ในกรณีนี้null) เพื่อแสดงถึงสองแนวคิดที่แตกต่างกันมาก (ในกรณีนี้การอ้างอิงที่ไม่ถูกต้องเทียบกับค่าที่ไม่มีอยู่ในฟิลด์ฐานข้อมูล)

โปรดทราบว่านี่คือเหตุผลที่ผู้คนจำนวนมากสนับสนุนการใช้รูปแบบวัตถุว่างโดยทั่วไปซึ่งเป็นSystem.DbNullตัวอย่างของ


43
+1 ตัวอย่างที่ใช้ได้จริง: หากคุณใช้IDbCommand.ExecuteScalar()มันสามารถคืนค่า null ได้ (ไม่มีการส่งคืนระเบียน) หรือDbNull(คอลัมน์แรกในระเบียนแรกเป็น 'ค่าที่ไม่มีอยู่') หากไม่มีDbNullคุณจะไม่สามารถแยกความแตกต่างจากอีกฝ่ายได้
C.Evenhuis

ฉันขอแนะนำอย่างยิ่งให้ใช้ภาษาที่ห้ามใช้ Null โดยมีค่าใช้จ่ายเพิ่มเติม 0 ชีวิตสั้นเกินไปสำหรับ "รูปแบบวัตถุว่าง"
ลัส

3
การอ้างอิงว่างนั้นใช้ได้อย่างสมบูรณ์ ☺
IllidanS4 รองรับ Monica

@ C.Evenhuis มีคำแนะนำทั่วไปอีกประการหนึ่งคือฟังก์ชันควรส่งคืนค่าประเภทเดียวเท่านั้น นั่นคือเหตุผลที่ผู้คนชอบรหัส TypeScript ที่พิมพ์ได้ดี "สถานะของการดำเนินการคืออะไร" แตกต่างจาก "ผลการคำนวณคืออะไร" ได้แก่ . พวกเขาอาจตัดสินใจที่จะใช้ฟังก์ชันนี้อย่างอื่น (อาจเป็นพารามิเตอร์ out หรือวัตถุที่คล้ายกับ objs การตอบสนองคำขอ HTTP) แน่นอนว่านี่เป็นภาวะแทรกซ้อนที่ไม่ต้องการจริงๆ แต่ถ้าพวกเขาทำเช่นนั้นอาจใช้ null แทน DbNull
klenium

21

จากเอกสารของคลาส DBNull :

อย่าสับสนระหว่างแนวคิดของ null ในภาษาโปรแกรมเชิงวัตถุกับวัตถุ DBNull ในภาษาโปรแกรมเชิงวัตถุ null หมายถึงการไม่มีการอ้างอิงถึงวัตถุ DBNull แสดงถึงตัวแปรที่ไม่ได้กำหนดค่าเริ่มต้นหรือคอลัมน์ฐานข้อมูลที่ไม่มีอยู่


11

DBNull.Value น่ารำคาญที่ต้องจัดการ

ฉันใช้วิธีการคงที่ตรวจสอบว่าเป็น DBNull หรือไม่จากนั้นส่งคืนค่า

SqlDataReader r = ...;
String firstName = getString(r[COL_Firstname]);

private static String getString(Object o) {
   if (o == DBNull.Value) return null;
   return (String) o;
}

นอกจากนี้เมื่อแทรกค่าลงใน DataRow คุณไม่สามารถใช้ "null" ได้คุณต้องใช้ DBNull.Value

การมีตัวแทนของ "null" สองรายการเป็นการออกแบบที่ไม่ดีโดยไม่มีประโยชน์อย่างชัดเจน


2
ความรู้สึกขยะแขยงที่เราแบ่งปันเรื่อง: คำพูดสุดท้ายของคุณได้รับความสนใจจากการแสดงที่นี่เพื่ออ่านสิ่งนี้และพบว่าชื่อผู้ใช้ของคุณ "เกลียดชัง"
Iofacture

5

DBNull.Value คือสิ่งที่ผู้ให้บริการฐานข้อมูล. NET ส่งคืนเพื่อแสดงรายการ null ในฐานข้อมูล DBNull.Value ไม่ใช่ null และการเปรียบเทียบกับ null สำหรับค่าคอลัมน์ที่ดึงมาจากแถวฐานข้อมูลจะไม่ทำงานคุณควรเปรียบเทียบกับ DBNull.Value เสมอ

http://msdn.microsoft.com/en-us/library/system.dbnull.value.aspx


ps คุณควรใช้ DBNull.Value เพื่อส่งผ่านพารามิเตอร์ null ไปยังฐานข้อมูลมิฉะนั้นอาจถูกตีความเนื่องจากไม่ได้ส่งผ่านพารามิเตอร์
James Michael Hare

1
DBNull ไม่ใช่ "สิ่งที่ฐานข้อมูลส่งคืน" แต่เป็นเพียงวิธีที่ ADO.NET เลือกตีความ โดยส่วนตัวฉันไม่แน่ใจว่าการตีความนี้มีค่ามาก
Marc Gravell

@MarcGravell ใช่มาร์คคุณพูดถูก ฉันพูดไม่ถูกต้อง ASP.NET แปลค่าคอลัมน์ฐานข้อมูล null เป็น DBNull.Value
James Michael Hare

3

DataRow มีวิธีการที่เรียกIsNull()ว่าคุณสามารถใช้เพื่อทดสอบคอลัมน์ว่ามีค่า null หรือไม่ซึ่งเกี่ยวกับ null ตามที่ฐานข้อมูลเห็น

DataRow["col"]==nullทั้งหมดจะเป็นfalseอย่างไร

ใช้

DataRow r;
if (r.IsNull("col")) ...

แทน.


3

null คล้ายกับศูนย์ชี้ใน C ++ ดังนั้นมันจึงเป็นข้อมูลอ้างอิงที่ไม่ได้ชี้ไปค่าใด

DBNull.Valueแตกต่างกันอย่างสิ้นเชิงและเป็นค่าคงที่ซึ่งจะส่งคืนเมื่อค่าของฟิลด์มีค่า NULL

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.