複数のDBMSから取得したDataTable比較

タグの編集
投稿者 YUU  (社会人) 投稿日時 2015/12/8 18:07:49

現在OracleとSqlserverから取得したDataTableを比較するプログラムを作成しております。

Oracleデータ ⇒ DataTable1
Sqlserverデータ ⇒ DataTable2

このご時世Entity Frameworkをなぜ使わぬといった話ですが今回はDataTableにて比較を行いたいと考えております。

http://qa.atmarkit.co.jp/q/9488

上記サイトを参考にLinq ラムダ式にて一つ一つループで回して比較するすべから逃れられそうなのですが如何せんC#の文法に苦戦しております。

現在最後に回答されている方の方式を.netの文法に置き換えているのですが置き換え方が分からない文法が有ります。(1人目の方はできました。)


Class DataRowComparer
    Implements IEqualityComparer(Of DataRow)

    Public Overloads Function Equals(x As DataRow, y As DataRow) As Boolean Implements IEqualityComparer(Of System.Data.DataRow).Equals
        Return Object.ReferenceEquals(x, y) OrElse (x IsNot Nothing AndAlso y IsNot Nothing AndAlso CompareAllColumns(x, y))
    End Function

    Private Function CompareAllColumns(x As DataRow, y As DataRow) As Boolean

        Dim intColumns As String() = New String() {"ID"}

        Return New String() {"ID", "Name"}.Select(Function(name) New With {.Name = name,
                                                                           .X = x(name),
                                                                           .Y = y(name),
                                                                           .IsInt = intColumns.Contains(name)}).Aggregate(True, Function(acc, succ)
                                                                                                                                    '下記のコメントアウト部分です。
                                                                                                                                    'if (DBNull.Value.Equals(succ.X) || DBNull.Value.Equals(succ.Y)) return acc && (succ.X?.Equals(succ.Y) ?? false);
                                                                                                                                    
    If succ.IsInt Then
                                                                                                                                        Return acc AndAlso (CInt(succ.X) = CInt(succ.Y))
                                                                                                                                    End If

                                                                                                                                    Return acc AndAlso (succ.X Is succ.Y)

                                                                                                                                End Function)

    End Function

    Public Overloads Function GetHashCode(obj As DataRow) As Integer Implements IEqualityComparer(Of System.Data.DataRow).GetHashCode

        If obj Is Nothing Then
            Return 0
        End If

        Dim idHashCode As Integer = If(obj("ID") Is Nothing, 0, obj("ID").GetHashCode())
        Dim nameHashCode As Integer = If(obj("Name") Is Nothing, 0, obj("Name").GetHashCode())

        Return idHashCode Xor nameHashCode

    End Function

End Class

上記のコメントアウト部分以外は.net文法に直せたかと思うのですがコメントの部分のみうまく変換できません。(それら以外は多分できたのかな?)

お力を貸していただけると幸いです。


投稿者 YuO  (社会人) 投稿日時 2015/12/8 18:35:11
.net文法というのがVisual Basicのことであるとして,
if (DBNull.Value.Equals(succ.X) || DBNull.Value.Equals(succ.Y)) return acc && (succ.X?.Equals(succ.Y) ?? false);

は,単純に||演算子をOrElseに,&&演算子をAndAlsoに,??演算子をIf式に置き換えて,
If DBNull.Value.Equals(succ.X) OrElse DBNull.Value.Equals(succ.Y) Then Return acc AndAlso If(succ.X?.Equals(succ.Y), False)
かと。
# 最近はDapper経由でオブジェクトに詰めてしまうことが多いなぁ……。
投稿者 YUU  (社会人) 投稿日時 2015/12/8 20:06:23
返信ありがとうございます。

変更後、確認をしたのですがやはりエラーが出てしまうみたいです。

If(succ.X?.Equals(succ.Y), False)部分にて二つのエラーが出ております。

○If演算子には2つまたは3つのオペランドが必要です。
○?文字はここでは使用できません。

上記のエラー内容です。ちなみにFrameWorksは4.0です。
投稿者 YuO  (社会人) 投稿日時 2015/12/8 23:43:43
.NET Frameworkのバージョンには関係しません。
ただし,.?演算子はVB14の追加機能なので,それより前のVBのコンパイラを使う場合は,コードをそれに対応させる必要があります。
幸い,?.演算子は
・オブジェクトがNothingでなければそのメンバーへのアクセスを行う
・オブジェクトがNothingであればメンバーへのアクセスを行わず,式の値はNothingになる
という演算子なので,ほぼ機械的にIf演算子に置き換えることができます。
# 値型に関して,元のメンバーアクセスの結果がT型ならばT?型になります。

If(succ.X?.Equals(succ.Y), False)
を直接置き換えるなら,
If(If(succ.X IsNot Nothing, succ.X.Equals(succ.Y), DirectCast(Nothing, Boolean?)), False)
でしょうか。
今回は内側のIf演算子がBoolean?型で,Nothingを返すのは条件がFalseの時のみであるため,二つのIf演算子をまとめて
If(succ.X IsNot Nothing, succ.X.Equals(succ.Y), False)
とした方が賢いですが。

ref)
What's New for Visual Basic : https://msdn.microsoft.com/ja-jp/library/we86c8x2(v=vs.140).aspx
Null 条件演算子 (C# および Visual Basic) : https://msdn.microsoft.com/ja-jp/library/dn986595(v=vs.140).aspx
投稿者 YUU  (社会人) 投稿日時 2015/12/9 13:52:58
返信ありがとうございました。

.?演算子知りませんでした。 勉強不足ですね、

ありがとうございます。無事実行できました。