2016-11-18 60 views
0
While CommitReader.Read() 
    Yield New Commit() With { 
     .FirstValue = CommitReader.GetInt32(CommitReader.GetOrdinal("FirstValue")), 
     .SecondValue = CommitReader.GetString(CommitReader.GetOrdinal("SecondValue")).Trim(), 
     'Lots of values 
End While 

我知道我可以做这样的事情;然而,有24个属性,我想尽可能使这个部分干净是否有一个整洁干净的方式来处理带有收益率的空值?

While CommitReader.Read() 
    new Commit(){ 
     Dim index As Integer = reader.GetOrdinal("FirstValue") 
     If reader.IsDBNull(index) Then 
      FirstValue = String.Empty 
     Else 
      FirstValue = reader(index) 
     End If 
     index = reader.GetOrdinal("SecondValue") 
     If reader.IsDBNull(index) Then 
      SecondValue = String.Empty 
     Else 
      SecondValue = reader(index) 
     End If 
    } 
End While 

有没有更好的方式来处理这种类型的事情?我主要是一个C#开发人员,所以如果语法有点遗憾,我会用VB来支持它。

+0

如果要将数据库NULL值转换为空字符串,可以在查询中执行此操作,例如, 'SELECT COALESCE(FirstValue,'')...'。 –

+0

@AndrewMorton,当你的解决方案工作的时候,你需要注意到这个更多关于你想在哪里保存这个逻辑的问题 - 在数据库层或业务逻辑层。如果你把它放在数据库层中,那么你的业务逻辑假定数据库层总是返回空字符串 – Fabio

+0

@Fabio是的,我同意丢失列数据为NULL的信息可能是一个问题。 –

回答

2

很遗憾SqlDataReader没有像DataRow那样的通用Field扩展方法,但是你可以定义你自己的扩展方法(必须在VB.NET模块中)以帮助进行空值检查,也许是这样的:

<Extension> 
Function GetValue(Of T)(rdr As SqlDataReader, i As Integer) As T 
    If rdr.IsDBNull(i) Then 
     Return Nothing 
    End If 
    Return DirectCast(rdr.GetValue(i), T) 
End Function 

而且使用它是这样的:

While CommitReader.Read() 
    Yield New Commit() With { 
     .FirstValue = CommitReader.GetValue(Of Integer?)(CommitReader.GetOrdinal("FirstValue")), 
     .SecondValue = CommitReader.GetValue(Of String)(CommitReader.GetOrdinal("SecondValue")), 
     'Lots of values 
End While 

我没有测试此完全以确保适当的处理所有数据类型(可能是值得考虑的DataRowExtensions.Field看看它是如何做到的)。

请注意,您正在使用String.Empty作为字符串的“null”值,而这将使用Nothing/null(我也必须删除.Trim调用以避免NRE)。如果你想为空字符串,而不是,您可以使用(加上修剪回):

.SecondValue = If(CommitReader.GetValue(Of String)(CommitReader.GetOrdinal("SecondValue")), String.Empty).Trim() 

您可能还需要移动GetOrdinal召唤出循环来提高性能。

+0

这个e类型对于所有原语是否安全,例如: DateTime,布尔? – Robert

+0

@Robert如果列是可空的,则需要使用可为空的基元类型作为泛型参数 - 如示例中的整数所示,例如, 'GetValue(Of DateTime?)',否则它将返回默认值,即DateTime.MinValue,或者对于整数类型返回0等。 – Mark

+0

这样做更有意义。谢谢 – Robert

1

显然你在代码if ... else ...的条件下有重复。
所以你可以用另一种方法提取它。

对于你的情况通用扩展方法似乎很好的候选人。

Public Module Extensions  
    <Extension> 
    Public Function GetValueOrDefault(Of T)(originalValue As object, 
              defaultValue As T) As T 
     If originalValue = DbNull.Value Then 
      Return defaultValue 
     End If 

     return DirectCast(originalValue, T) 
    End Function 
End Module 

然后使用它:

While CommitReader.Read() = True 
    Dim temp = new Commit With 
    { 
     Dim index As Integer = reader.GetOrdinal("FirstValue") 
     FirstValue = reader(index).GetValueOrDefault(String.Empty) 

     Dim index As Integer = reader.GetOrdinal("SecondValue") 
     FirstValue = reader(index).GetValueOrDefault(String.Empty)  
    } 
End While 

您可以创建另一个重载其返回给定类型的 “默认” 值,如果它是DbNull

<Extension> 
Public Function GetValueOrDefault(Of T)(originalValue As object) As T 
    Return originalValue.GetValueOrDefault(Nothing) 
End Function 

在vb.net Nothing是默认值,对于参考类型,它是null,对于Integer,例如是0

对于使用此重载你需要提供类型参数明确

While CommitReader.Read() = True 
    Dim temp = new Commit With 
    { 
     Dim index As Integer = reader.GetOrdinal("FirstValue") 
     FirstValue = reader(index).GetValueOrDefault(Of String)() 

     Dim index As Integer = reader.GetOrdinal("SecondValue") 
     FirstValue = reader(index).GetValueOrDefault(Of String)()  
    } 
End While 

请注意,您的解决方案执行reader两次,检查是不是空和阅读价值。这可能会导致“微小”的性能问题。

因此,在上述扩展方法中,我们只读取一次值,然后检查DbNull的值。

0

如果您连接使用空字符串所得到的字符串:

的“不专业”的种类,但是节省了大量的编码时间,如果你正在做的是将一个可能的空空字符串。然而容易忘记,所以后面的数据依赖错误可能会弹出。

+0

如何“不专业”的解决方案_...所以后来的数据相关的错误可能会弹出_可以节省编码时间? – Fabio

+0

可能会出现此错误,因为作为编码器,您可能忘记添加空字符串。如果您的数据很少遇到空值,但数据库中可能为空,则可能会发生错误。最好能抵御已知可能的情况。 – rheitzman

相关问题