2

かなり頻繁に私は自分がこのようなコードを書いていることに気づきます:

Dim oRenewalOrder = (From c in dc.Orders _
                     Where c.CustomerID = iCustomerID _
                     And c.Type = "RENEWAL").FirstOrDefault()

If oRenewalOrder Is Nothing Then
   Throw New Exception("Can't find renewal order for customer " & iCustomerID) ' or assert, if you prefer
End If

' Continue processing...

代わりにFirst()メソッドを使用することをお勧めします。これは、要素がない場合にすでに例外がスローされるためです。しかし、その例外は原因について何も教えてくれないため、デバッグが難しくなります。したがって、次のように使用できるFirstOrException()拡張メソッドを記述します。

Dim oRenewalOrder = (From c in dc.Orders _
                     Where c.CustomerID = iCustomerID _
                     And c.Type = "RENEWAL").FirstOrException("Can't find renewal order for customer " & iCustomerID)

' Continue processing...

問題は、このようなメソッドを一般的な方法で記述し、LINQ to Objectsの両方を操作し、LINQtoSQLのクエリ最適化を利用するのが難しいことです。私が思いつくことができる最高のものはこれです:

    ''' <summary>
    ''' Returns the first element of a sequence.
    ''' If the sequence is empty, an InvalidOperationException is thrown with the specified message.
    <Extension()> _
    Function FirstOrException(Of T)(ieThis As IEnumerable(Of T), sMessage As String) As T
        Try
            Return ieThis.First()
        Catch ex As InvalidOperationException
            Throw New InvalidOperationException(sMessage, ex)
        End Try
    End Function

また、LINQ to Objectsの場合をカバーするために、IEnumerable(Of T)の別の同等の拡張メソッドを作成しました。これらはうまく機能しますが、例外をキャッチして再スローする必要があるのは悪いことのようです。Take(1)とAsEnumerable()を使用して別のアプローチを試しましたが、プロファイルを作成すると、2つの別々のSELECTTOP1ステートメントが実行されていました。

    <Extension()> _
    Function FirstOrException(Of T)(iqThis As IQueryable(Of T), sMessage As String) As T
        Dim aFirst = iqThis.Take(1).AsEnumerable()
        If aFirst.Count() <= 0 Then
            Throw New InvalidOperationException(sMessage)
        Else
            Return aFirst(0)
        End If
    End Function

それで、例外処理メソッドに戻ります。別の問題(結果の欠如ではなく、何か他の問題)がある場合、コレクションの基になるLINQプロバイダーがInvalidOperationExceptionをスローする可能性があるため、私はそれが好きではありません。これにより、実際にはまったく別の問題であったにもかかわらず、コードが結果がないと誤って判断する可能性があります。

..。

さて、あなたが詳細な質問をタイプするときによくあることですが、私はより良い解決策を見つけたと思います、そして私はそれを以下の答えに投稿します。しかし、誰かがもっと良いものを見つけた場合に備えて、質問は開いたままにしておきます:-)

4

2 に答える 2

0

私はそれTake(1).ToArray()が最もクリーンな解決策であることがわかりました。これにより、データベースに送信されるクエリは1つだけになります。以下のコードでは、LINQtoSQLとLINQtoObjectsの両方をサポートするために、IEnumerableとIQueryableに対して別々の拡張メソッドを実行していることに注意してください。

    ''' <summary>
    ''' Returns the first element of a sequence.
    ''' If the sequence is empty, an InvalidOperationException is thrown with the specified message.
    <Extension()> _
    Function FirstOrException(Of T)(ieThis As IEnumerable(Of T), sMessage As String) As T
        Dim aFirst = ieThis.Take(1).ToArray()
        If aFirst.Length <= 0 Then
            Throw New InvalidOperationException(sMessage)
        Else
            Return aFirst(0)
        End If
    End Function

     ''' <summary>
     ''' Returns the first element of a queryable (e.g. LINQ to SQL) sequence.
     ''' If the sequence is empty, an InvalidOperationException is thrown with the specified message.
    <Extension()> _
    Function FirstOrException(Of T)(iqThis As IQueryable(Of T), sMessage As String) As T
        Dim aFirst = iqThis.Take(1).AsEnumerable()
        If aFirst.Length <= 0 Then
            Throw New InvalidOperationException(sMessage)
        Else
            Return aFirst(0)
        End If
    End Function
于 2012-08-11T00:59:03.977 に答える
0

Linq-to-sqlの最適化を変更せずに、すでに拡張を実行しました。そこに何かがあるかどうかを確認するには、少なくとも1回はデータベースにアクセスする必要があります。を使用する必要はありません。Take(1)呼び出しFirstOrDefault()て、が返されるかどうかを確認してくださいNothing

Function GetFirstOrException(Of T)(sMessage As String, sFirst as T) as T
   if (T is Nothing) 
      Throw New InvalidOperationException(sMessage)
   Return T
End Function

 <Extension()> _
Function FirstOrException(Of T)(iqThis As IQueryable(Of T), sMessage As String) As T
    Return GetFirstOrException(sMessage, idThis.FirstOrDefault())
End Function

 <Extension()> _
Function FirstOrException(Of T)(iqThis As IEnumerable(Of T), sMessage As String) As T
    Return GetFirstOrException(sMessage, idThis.FirstOrDefault())
End Function
于 2012-08-11T20:35:35.533 に答える