วิธีที่มีประสิทธิภาพมากที่สุดในการตรวจสอบ DBNull แล้วกำหนดให้กับตัวแปรหรือไม่


151

คำถามนี้เกิดขึ้นเป็นครั้งคราว แต่ฉันไม่เห็นคำตอบที่น่าพอใจ

รูปแบบทั่วไปคือ (แถวคือDataRow ):

 if (row["value"] != DBNull.Value)
 {
      someObject.Member = row["value"];
 }

คำถามแรกของฉันคือคำถามใดมีประสิทธิภาพมากขึ้น (ฉันพลิกเงื่อนไข):

  row["value"] == DBNull.Value; // Or
  row["value"] is DBNull; // Or
  row["value"].GetType() == typeof(DBNull) // Or... any suggestions?

สิ่งนี้บ่งชี้ว่า. GetType () ควรจะเร็วกว่านี้ แต่บางทีคอมไพเลอร์ก็รู้เทคนิคเล็กน้อยที่ฉันไม่ต้องการ

คำถามที่สองมันคุ้มค่าที่จะแคชค่าของแถว ["value"] หรือคอมไพเลอร์ปรับดัชนีให้เหมาะสมหรือไม่?

ตัวอย่างเช่น:

  object valueHolder;
  if (DBNull.Value == (valueHolder = row["value"])) {}

หมายเหตุ:

  1. มีแถว ["ค่า"] อยู่
  2. ฉันไม่รู้ดัชนีคอลัมน์ของคอลัมน์ (ดังนั้นการค้นหาชื่อคอลัมน์)
  3. ฉันถามเฉพาะเกี่ยวกับการตรวจสอบ DBNull แล้วมอบหมาย (ไม่เกี่ยวกับการปรับให้เหมาะสมก่อนเวลา ฯลฯ )

ฉันเปรียบเทียบกับบางสถานการณ์ (เวลาเป็นวินาทีการทดลอง 10,000,000 ครั้ง):

row["value"] == DBNull.Value: 00:00:01.5478995
row["value"] is DBNull: 00:00:01.6306578
row["value"].GetType() == typeof(DBNull): 00:00:02.0138757

Object.ReferenceEquals มีประสิทธิภาพเช่นเดียวกับ "=="

ผลลัพธ์ที่น่าสนใจที่สุด? หากคุณไม่ตรงกับชื่อของคอลัมน์ตามแต่ละกรณี (ตัวอย่างเช่น "Value" แทนที่จะเป็น "value" จะใช้เวลานานกว่าประมาณสิบเท่า (สำหรับสตริง):

row["Value"] == DBNull.Value: 00:00:12.2792374

คุณธรรมของเรื่องราวดูเหมือนว่าถ้าคุณไม่สามารถค้นหาคอลัมน์ด้วยดัชนีได้ให้แน่ใจว่าชื่อคอลัมน์ที่คุณป้อนไปยังตัวทำดัชนีตรงกับชื่อของ DataColumn

การแคชค่าดูเหมือนจะเร็วเป็นสองเท่า:

No Caching: 00:00:03.0996622
With Caching: 00:00:01.5659920

ดังนั้นวิธีที่มีประสิทธิภาพที่สุดน่าจะเป็น:

 object temp;
 string variable;
 if (DBNull.Value != (temp = row["value"]))
 {
      variable = temp.ToString();
 }

1
คุณสามารถอธิบายได้ว่าแถวคือ DataRow หรือ IDataRecord / IDataReader หรือไม่
Marc Gravell

7
ตอนนี้เรามีดีมาก .NET Framework และเราสามารถใช้DataRowExtensions วิธี
Pavel Hodek

หากคุณไม่ตรงกับชื่อของคอลัมน์ตามแต่ละกรณี (ตัวอย่างเช่น "Value" แทนที่จะเป็น "value" จะใช้เวลานานกว่าประมาณสิบเท่า (สำหรับสตริง) สิ่งนี้ขึ้นอยู่กับการนำไปใช้อย่างสมบูรณ์ฉันจำได้ว่านี่เป็นกรณี (เปลี่ยน กรณีของชื่อคอลัมน์จะช้ากว่ามาก) ด้วยตัวเชื่อมต่อ MySQL ADO.NET แต่ไม่เลยสำหรับ SqlServer หรือ SQLite (จำไม่ได้) สิ่งต่าง ๆ อาจมีการเปลี่ยนแปลงในขณะนี้ใช่แนวทางพื้นฐานคือเมื่อมีข้อสงสัยให้ไปตามลำดับ
nawfal

@PavelHodek เช่นนี้เป็นความอัปยศสำหรับ DataRow เท่านั้น จะมีIDataRecordส่วนขยายที่รัก
nawfal

คำตอบ:


72

ฉันต้องคิดถึงบางสิ่ง ไม่ได้ตรวจสอบDBNullสิ่งที่DataRow.IsNullวิธีการทำอย่างแน่นอน?

ฉันใช้วิธีส่วนขยายสองวิธีต่อไปนี้:

public static T? GetValue<T>(this DataRow row, string columnName) where T : struct
{
    if (row.IsNull(columnName))
        return null;

    return row[columnName] as T?;
}

public static string GetText(this DataRow row, string columnName)
{
    if (row.IsNull(columnName))
        return string.Empty;

    return row[columnName] as string ?? string.Empty;
}

การใช้งาน:

int? id = row.GetValue<int>("Id");
string name = row.GetText("Name");
double? price = row.GetValue<double>("Price");

หากคุณไม่ต้องการNullable<T>ค่าตอบแทนสำหรับGetValue<T>คุณสามารถคืนค่าได้อย่างง่ายดายdefault(T)หรือมีตัวเลือกอื่นแทน


ในบันทึกที่ไม่เกี่ยวข้องนี่เป็นทางเลือก VB.NET สำหรับคำแนะนำของ Stevo3000:

oSomeObject.IntMember = If(TryConvert(Of Integer)(oRow("Value")), iDefault)
oSomeObject.StringMember = If(TryCast(oRow("Name"), String), sDefault)

Function TryConvert(Of T As Structure)(ByVal obj As Object) As T?
    If TypeOf obj Is T Then
        Return New T?(DirectCast(obj, T))
    Else
        Return Nothing
    End If
End Function

3
แดนนี้มีความเสี่ยงอีกครั้งสิ่งที่ OP ต้องการหลีกเลี่ยง โดยการเขียนrow.IsNull(columnName)คุณอ่านมันแล้วและอ่านอีกครั้ง ไม่ได้บอกว่าจะสร้างความแตกต่าง แต่ในทางทฤษฎีก็สามารถที่จะมีประสิทธิภาพน้อยลง ..
Nawfal

2
ไม่ได้System.Data.DataSetExtensions.DataRowExtensions.Field<T>(this System.Data.DataRow, string)ทำสิ่งเดียวกับวิธีแรกใช่หรือไม่
Dennis G

35

คุณควรใช้วิธีการ:

Convert.IsDBNull()

เมื่อพิจารณาว่ามันมีอยู่ใน Framework แล้วฉันคาดว่าสิ่งนี้จะมีประสิทธิภาพมากที่สุด

ฉันขอแนะนำบางสิ่งตามแนวของ:

int? myValue = (Convert.IsDBNull(row["column"]) ? null : (int?) Convert.ToInt32(row["column"]));

และใช่คอมไพเลอร์ควรแคชให้คุณ


5
ดีทุกตัวเลือกดังกล่าวถูกสร้างขึ้นในกรอบ ... ที่จริง Convert.IsDBNull ไม่ทำงานมากเป็นพิเศษเกี่ยวกับการ IConvertible แล้ว ...
Marc Gravell

1
และแคชอีกครั้ง - ถ้าคุณหมายถึงตัวอย่างที่มีเงื่อนไขไม่ใช่ - ไม่ควร (และไม่ทำ) มันจะรันตัวสร้างดัชนีสองครั้ง
Marc Gravell

โอ้และรหัสนั้นไม่ได้รวบรวม - แต่เพิ่ม (int?) หนึ่งในนั้นและคุณจะเห็น (ใน IL) 2 จาก: วัตถุอินสแตนซ์ callvirt [System.Data] System.Data.DataRow :: get_Item (สตริง)
Marc Gravell

20

คอมไพเลอร์จะไม่ปรับตัวทำดัชนีให้เหมาะสม (เช่นถ้าคุณใช้แถว ["ค่า"] สองครั้ง) ดังนั้นใช่มันเร็วกว่าเล็กน้อยที่จะทำ:

object value = row["value"];

จากนั้นใช้ค่าสองครั้ง การใช้. GETType () มีความเสี่ยงหากเป็นโมฆะ ...

DBNull.Valueจริง ๆ แล้วเป็นซิงเกิลดังนั้นเพื่อเพิ่มตัวเลือกที่ 4 - บางทีคุณอาจใช้ ReferenceEquals - แต่ในความเป็นจริงฉันคิดว่าคุณกังวลมากเกินไปที่นี่ ... ฉันไม่คิดว่าความเร็วแตกต่างกันระหว่าง "คือ", "== "ฯลฯ จะเป็นสาเหตุของปัญหาประสิทธิภาพการทำงานที่คุณเห็น โปรไฟล์รหัสทั้งหมดของคุณและมุ่งเน้นไปที่สิ่งที่สำคัญ ... มันจะไม่เป็นเช่นนี้


2
ในทุกกรณี == จะเท่ากับ ReferenceEquals (โดยเฉพาะกับ DBNull) และสามารถอ่านได้มากขึ้น ใช้การเพิ่มประสิทธิภาพของ @Marc Gravell หากคุณต้องการ แต่ฉันอยู่กับเขา - อาจจะไม่ช่วยอะไรมาก BTW ความเสมอภาคอ้างอิงควรเอาชนะการตรวจสอบประเภทเสมอ
tvanfosson

1
เก่าตอนนี้ แต่เมื่อเร็ว ๆ นี้ฉันเคยเห็นหลายกรณีที่สิ่งนี้เป็นสิ่งที่ผู้สร้างโปรไฟล์พูดเพื่อแก้ไข ลองนึกภาพการประเมินชุดข้อมูลขนาดใหญ่ที่ทุกเซลล์ต้องการทำการตรวจสอบนี้ การเพิ่มประสิทธิภาพที่สามารถรับรางวัลใหญ่ ๆ ได้ แต่ส่วนที่สำคัญของคำตอบก็ยังดี: ประวัติก่อนเพื่อทราบว่าจะใช้เวลาของคุณให้ดีที่สุด
Joel Coehoorn

ฉันเดาการแนะนำตัวดำเนินการ Elvis C # 6 ทำให้ง่ายต่อการหลีกเลี่ยงข้อยกเว้นการอ้างอิงว่างในการตรวจสอบที่คุณแนะนำ ค่า? .GetType () == typeof (DBNull)
Eniola

ใช่ฉันเห็นด้วย. โดยทั่วไปเป็นวิธีที่ดีกว่าที่จะไป แต่สำหรับผู้ที่ต้องการใช้. GetType () ที่มีความเสี่ยงที่คุณชี้ให้เห็นแล้ว? ให้ทางรอบ ๆ มัน
Eniola

9

ฉันจะใช้รหัสต่อไปนี้ใน C # ( VB.NETไม่ง่ายเหมือน)

รหัสจะกำหนดค่าหากไม่ใช่ค่า Null / DBNull มิฉะนั้นจะกำหนดค่าเริ่มต้นซึ่งสามารถกำหนดเป็นค่า LHS เพื่อให้คอมไพเลอร์ละเว้นการมอบหมาย

oSomeObject.IntMemeber = oRow["Value"] as int? ?? iDefault;
oSomeObject.StringMember = oRow["Name"] as string ?? sDefault;

1
รุ่น VB.NET คือoSomeObject.IntMember = If(TryCast(oRow("Value), Integer?), iDefault)เป็นง่ายๆ:
Dan Tao

1
@Dan Tao - ฉันไม่คิดว่าคุณรวบรวมรหัสนั้น ดูคำถามเก่า ๆ ของฉันซึ่งอธิบายว่าทำไมรหัสของคุณถึงใช้งานไม่ได้ stackoverflow.com/questions/746767/…
stevehipwell

และอีกครั้งการแสดงความคิดเห็นเกี่ยวกับคำถาม SO ในขณะที่อยู่ห่างจากคอมพิวเตอร์ของฉัน (พร้อมเครื่องมือ dev ในนั้น) ได้พิสูจน์แล้วว่าเป็นข้อผิดพลาด! คุณพูดถูก ฉันประหลาดใจที่จะเรียนรู้ที่TryCastจะไม่ให้ฟังก์ชันการทำงานที่สะดวกสบายเช่นเดียวกับ C # 's asประกอบการสำหรับNullable(Of T)ประเภท วิธีที่ใกล้เคียงที่สุดที่ฉันสามารถนึกได้ในการเลียนแบบนี้คือการเขียนฟังก์ชั่นของคุณเองตามที่ฉันได้แนะนำไว้ในคำตอบของฉัน
Dan Tao

คุณจะต้องปรับโครงสร้างนี้เป็นวิธีที่ยากลำบากและถึงแม้ว่าคุณจะทำการหล่อที่เกี่ยวข้องมากเกินไปก็จะทำให้ประสิทธิภาพลดลง
nawfal

8

ฉันรู้สึกว่ามีเพียงไม่กี่วิธีที่นี่ที่จะไม่เสี่ยงกับความกังวลของ OP (Marc Gravell, Stevo3000, Richard Szalay, Neil, Darren Koppand) และที่ซับซ้อนโดยไม่จำเป็น การตระหนักอย่างเต็มที่ว่านี่คือการเพิ่มประสิทธิภาพขนาดเล็กที่ไม่มีประโยชน์ให้ฉันบอกว่าคุณควรใช้สิ่งเหล่านี้

1) อย่าอ่านค่าจาก DataReader / DataRow สองครั้งดังนั้นให้ทำการแคชก่อนตรวจสอบค่าว่างและปลดเปลื้อง / แปลงหรือดีกว่าส่งrecord[X]วัตถุของคุณโดยตรงไปยังวิธีการขยายที่กำหนดเองพร้อมลายเซ็นที่เหมาะสม

2) ในการเชื่อฟังข้างต้นอย่าใช้IsDBNullฟังก์ชั่นบิวด์อินใน DataReader / DataRow ของคุณเนื่องจากการเรียกrecord[X]ภายในนั้นดังนั้นคุณจะต้องทำสองครั้ง

3) การเปรียบเทียบชนิดจะช้ากว่าการเปรียบเทียบค่าตามกฎทั่วไปเสมอ ทำได้record[X] == DBNull.Valueดีกว่า

4) การร่ายโดยตรงจะเร็วกว่าการเรียกConvertคลาสสำหรับการเปลี่ยนใจเลื่อมใส

5) สุดท้ายการเข้าถึงการบันทึกโดยใช้ดัชนีแทนที่จะเป็นชื่อคอลัมน์จะเร็วขึ้นอีกครั้ง


ฉันรู้สึกว่าไปตามแนวทางของ Szalay, Neil และ Darren Koppand จะดีกว่า ฉันชอบวิธีการขยายของ Darren Koppand โดยเฉพาะอย่างยิ่งซึ่งใช้เวลาในIDataRecord(แม้ว่าฉันต้องการที่จะแคบลงไปอีกIDataReader) และชื่อดัชนี / คอลัมน์

ระวังที่จะเรียกมันว่า:

record.GetColumnValue<int?>("field");

และไม่

record.GetColumnValue<int>("field");

ในกรณีที่คุณต้องการความแตกต่างระหว่างและ0 DBNullตัวอย่างเช่นหากคุณมีค่า Null ในฟิลด์ enum มิฉะนั้นdefault(MyEnum)ความเสี่ยงจะส่งคืนค่า enum ก่อน record.GetColumnValue<MyEnum?>("Field")ดังนั้นการเรียกร้องที่ดีกว่า

เนื่องจากคุณกำลังอ่านจาก a DataRowฉันจะสร้างวิธีการขยายสำหรับทั้งสองDataRowและIDataReaderโดยทั่วไปรหัสDRYing

public static T Get<T>(this DataRow dr, int index, T defaultValue = default(T))
{
    return dr[index].Get<T>(defaultValue);
}

static T Get<T>(this object obj, T defaultValue) //Private method on object.. just to use internally.
{
    if (obj.IsNull())
        return defaultValue;

    return (T)obj;
}

public static bool IsNull<T>(this T obj) where T : class 
{
    return (object)obj == null || obj == DBNull.Value;
} 

public static T Get<T>(this IDataReader dr, int index, T defaultValue = default(T))
{
    return dr[index].Get<T>(defaultValue);
}

ดังนั้นตอนนี้เรียกว่า:

record.Get<int>(1); //if DBNull should be treated as 0
record.Get<int?>(1); //if DBNull should be treated as null
record.Get<int>(1, -1); //if DBNull should be treated as a custom value, say -1

ผมเชื่อว่านี่เป็นวิธีการที่ควรจะได้รับในกรอบ (แทนrecord.GetInt32, record.GetStringวิธีการ ฯลฯ ) ในสถานที่แรก - ไม่มีข้อยกเว้นเวลาทำงานและช่วยให้เรามีความยืดหยุ่นในการค่า null จับ

จากประสบการณ์ของฉันฉันมีโชคน้อยลงด้วยวิธีทั่วไปหนึ่งวิธีในการอ่านจากฐานข้อมูล ฉันมักจะมีการจับที่กำหนดเองประเภทต่าง ๆ เพื่อให้ฉันได้เขียนของตัวเองGetInt, GetEnum, GetGuidวิธีการอื่น ๆ ในระยะยาว ถ้าคุณต้องการตัดช่องว่างสีขาวเมื่ออ่านสตริงจาก db โดยค่าเริ่มต้นหรือถือว่าDBNullเป็นสตริงว่าง หรือถ้าทศนิยมของคุณควรถูกตัดทอนจากศูนย์ทั้งหมดต่อท้าย ฉันมีปัญหามากที่สุดกับGuidประเภทที่ไดรเวอร์ตัวเชื่อมต่อที่แตกต่างกันทำงานแตกต่างกันเช่นกันเมื่อฐานข้อมูลพื้นฐานสามารถเก็บไว้เป็นสตริงหรือไบนารี ฉันมีงานล้นมือเช่นนี้:

static T Get<T>(this object obj, T defaultValue, Func<object, T> converter)
{
    if (obj.IsNull())
        return defaultValue;

    return converter  == null ? (T)obj : converter(obj);
}

ด้วยวิธีการของ Stevo3000 ฉันพบว่าการโทรนั้นค่อนข้างน่าเกลียดและน่าเบื่อและมันจะยากกว่าที่จะสร้างฟังก์ชั่นทั่วไปออกมาจากมัน


7

มีกรณีที่ลำบากซึ่งวัตถุอาจเป็นสตริงได้ โค้ดวิธีการขยายด้านล่างจัดการทุกกรณี นี่คือวิธีที่คุณจะใช้:

    static void Main(string[] args)
    {
        object number = DBNull.Value;

        int newNumber = number.SafeDBNull<int>();

        Console.WriteLine(newNumber);
    }



    public static T SafeDBNull<T>(this object value, T defaultValue) 
    {
        if (value == null)
            return default(T);

        if (value is string)
            return (T) Convert.ChangeType(value, typeof(T));

        return (value == DBNull.Value) ? defaultValue : (T)value;
    } 

    public static T SafeDBNull<T>(this object value) 
    { 
        return value.SafeDBNull(default(T)); 
    } 

6

ฉันชอบไวยากรณ์นี้เป็นการส่วนตัวซึ่งใช้วิธี IsDbNull ที่เปิดเผยอย่างชัดเจนIDataRecordและแคชดัชนีคอลัมน์เพื่อหลีกเลี่ยงการค้นหาสตริงที่ซ้ำกัน

ขยายให้อ่านง่ายมันมีลักษณะดังนี้:

int columnIndex = row.GetOrdinal("Foo");
string foo; // the variable we're assigning based on the column value.
if (row.IsDBNull(columnIndex)) {
  foo = String.Empty; // or whatever
} else { 
  foo = row.GetString(columnIndex);
}

เขียนซ้ำเพื่อให้พอดีกับบรรทัดเดียวเพื่อความกะทัดรัดในรหัส DAL - โปรดทราบว่าในตัวอย่างนี้เราจะกำหนดint bar = -1ถ้าrow["Bar"]เป็นโมฆะ

int i; // can be reused for every field.
string foo  = (row.IsDBNull(i  = row.GetOrdinal("Foo")) ? null : row.GetString(i));
int bar = (row.IsDbNull(i = row.GetOrdinal("Bar")) ? -1 : row.GetInt32(i));

การกำหนดแบบอินไลน์อาจสร้างความสับสนหากคุณไม่รู้ว่ามี แต่การดำเนินการทั้งหมดในหนึ่งบรรทัดซึ่งฉันคิดว่าช่วยเพิ่มความสามารถในการอ่านเมื่อคุณเติมคุณสมบัติจากหลายคอลัมน์ในรหัสบล็อกหนึ่งบล็อก


3
DataRow ไม่ได้ใช้งาน IDataRecord
ilitirit

5

ไม่ใช่ว่าฉันได้ทำสิ่งนี้ไปแล้ว แต่คุณสามารถโทรหาตัวจัดดัชนีสองครั้งและยังคงรักษาโค้ดของคุณให้สะอาดได้โดยใช้วิธี static / extension

กล่าวคือ

public static IsDBNull<T>(this object value, T default)
{
    return (value == DBNull.Value)
        ? default
        : (T)value;
}

public static IsDBNull<T>(this object value)
{
    return value.IsDBNull(default(T));
}

แล้ว:

IDataRecord record; // Comes from somewhere

entity.StringProperty = record["StringProperty"].IsDBNull<string>(null);
entity.Int32Property = record["Int32Property"].IsDBNull<int>(50);

entity.NoDefaultString = record["NoDefaultString"].IsDBNull<string>();
entity.NoDefaultInt = record["NoDefaultInt"].IsDBNull<int>();

ยังมีประโยชน์ในการรักษาตรรกะการตรวจสอบว่างในที่เดียว ข้อเสียคือแน่นอนว่ามันเป็นวิธีการโทรพิเศษ

แค่ความคิด


2
แม้ว่าการเพิ่มวิธีการขยายบนวัตถุนั้นกว้างมาก ส่วนตัวฉันอาจพิจารณาวิธีการขยายใน DataRow แต่ไม่ใช่วัตถุ
Marc Gravell

จริง แต่โปรดจำไว้ว่าวิธีการขยายจะใช้ได้เฉพาะเมื่อมีการนำเข้าเนมสเปซของคลาสส่วนขยาย
Richard Szalay

5

ฉันพยายามหลีกเลี่ยงการตรวจสอบนี้ให้มากที่สุด

เห็นได้ชัดว่าไม่จำเป็นต้องทำสำหรับคอลัมน์ที่ไม่สามารถถือได้ nullได้

หากคุณกำลังจัดเก็บในประเภทค่า Nullable ( int?ฯลฯ ) as int?คุณก็สามารถแปลงโดยใช้

หากคุณไม่จำเป็นต้องมีความแตกต่างระหว่างstring.Emptyและnullคุณก็สามารถโทรหา.ToString()ตั้งแต่ DBNull string.Emptyจะกลับมา



4

นี่คือวิธีที่ฉันจัดการกับการอ่านจาก DataRows

///<summary>
/// Handles operations for Enumerations
///</summary>
public static class DataRowUserExtensions
{
    /// <summary>
    /// Gets the specified data row.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="dataRow">The data row.</param>
    /// <param name="key">The key.</param>
    /// <returns></returns>
    public static T Get<T>(this DataRow dataRow, string key)
    {
        return (T) ChangeTypeTo<T>(dataRow[key]);
    }

    private static object ChangeTypeTo<T>(this object value)
    {
        Type underlyingType = typeof (T);
        if (underlyingType == null)
            throw new ArgumentNullException("value");

        if (underlyingType.IsGenericType && underlyingType.GetGenericTypeDefinition().Equals(typeof (Nullable<>)))
        {
            if (value == null)
                return null;
            var converter = new NullableConverter(underlyingType);
            underlyingType = converter.UnderlyingType;
        }

        // Try changing to Guid  
        if (underlyingType == typeof (Guid))
        {
            try
            {
                return new Guid(value.ToString());
            }
            catch

            {
                return null;
            }
        }
        return Convert.ChangeType(value, underlyingType);
    }
}

ตัวอย่างการใช้งาน:

if (dbRow.Get<int>("Type") == 1)
{
    newNode = new TreeViewNode
                  {
                      ToolTip = dbRow.Get<string>("Name"),
                      Text = (dbRow.Get<string>("Name").Length > 25 ? dbRow.Get<string>("Name").Substring(0, 25) + "..." : dbRow.Get<string>("Name")),
                      ImageUrl = "file.gif",
                      ID = dbRow.Get<string>("ReportPath"),
                      Value = dbRow.Get<string>("ReportDescription").Replace("'", "\'"),
                      NavigateUrl = ("?ReportType=" + dbRow.Get<string>("ReportPath"))
                  };
}

อุปกรณ์ประกอบฉากเพื่อสัตว์ประหลาดได้รับ. สุทธิของฉันสำหรับรหัส ChageTypeTo


4

ฉันทำสิ่งที่คล้ายกับวิธีการขยาย นี่คือรหัสของฉัน:

public static class DataExtensions
{
    /// <summary>
    /// Gets the value.
    /// </summary>
    /// <typeparam name="T">The type of the data stored in the record</typeparam>
    /// <param name="record">The record.</param>
    /// <param name="columnName">Name of the column.</param>
    /// <returns></returns>
    public static T GetColumnValue<T>(this IDataRecord record, string columnName)
    {
        return GetColumnValue<T>(record, columnName, default(T));
    }

    /// <summary>
    /// Gets the value.
    /// </summary>
    /// <typeparam name="T">The type of the data stored in the record</typeparam>
    /// <param name="record">The record.</param>
    /// <param name="columnName">Name of the column.</param>
    /// <param name="defaultValue">The value to return if the column contains a <value>DBNull.Value</value> value.</param>
    /// <returns></returns>
    public static T GetColumnValue<T>(this IDataRecord record, string columnName, T defaultValue)
    {
        object value = record[columnName];
        if (value == null || value == DBNull.Value)
        {
            return defaultValue;
        }
        else
        {
            return (T)value;
        }
    }
}

หากต้องการใช้งานคุณจะทำสิ่งที่ชอบ

int number = record.GetColumnValue<int>("Number",0)

4

ถ้าใน DataRow แถว ["fieldname"] isDbNull แทนที่ด้วย 0 มิฉะนั้นจะได้รับค่าทศนิยม:

decimal result = rw["fieldname"] as decimal? ?? 0;

3
public static class DBH
{
    /// <summary>
    /// Return default(T) if supplied with DBNull.Value
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value"></param>
    /// <returns></returns>
    public static T Get<T>(object value)
    {   
        return value == DBNull.Value ? default(T) : (T)value;
    }
}

ใช้แบบนี้

DBH.Get<String>(itemRow["MyField"])

3

ฉันมี IsDBNull ในโปรแกรมที่อ่านข้อมูลจำนวนมากจากฐานข้อมูล ด้วย IsDBNull จะโหลดข้อมูลในเวลาประมาณ 20 วินาที ไม่มี IsDBNull ประมาณ 1 วินาที

ดังนั้นฉันคิดว่ามันจะดีกว่าที่จะใช้:

public String TryGetString(SqlDataReader sqlReader, int row)
{
    String res = "";
    try
    {
        res = sqlReader.GetString(row);
    }
    catch (Exception)
    { 
    }
    return res;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.