2015-08-14 1 views
0

Мне нужна помощь в определении того, как это сделать. У меня есть DataSet, который содержит записи по дате и currencyCode. Я хочу сравнить два набора данных и узнать, есть ли одна (левая таблица) записи, существует don't на второй (правой) таблицы, я следующий код для соединения таблицы на основе даты и кода:Получение только записей не во второй таблице LINQ

vLINQ = (From ContentExchangeRates In myDataset.Tables(0).AsEnumerable() _ 
     Join PartnerExchangeRates In PartnerDataSet.Tables(0).AsEnumerable() _ 
     On ContentExchangeRates.Field(Of Date)("EffectiveDate") Equals PartnerExchangeRates.Field(Of Date)("RateDate") _ 
     And ContentExchangeRates.Field(Of String)("CurrencyCode") Equals PartnerExchangeRates.Field(Of Date)("CurrencyCode") _ 
     Select New With { .PartnerRateDate = PartnerExchangeRates.Field(Of Date)("RateDate"), _ etc}).ToList 

Использование Джеффа ответа код выглядит следующим образом:

vLINQ = (From ContentExchangeRates In myDataSet.Tables(0).AsEnumerable() _ 
           Group Join PartnerExchangeRates In PartnerDataSet.Tables(0).AsEnumerable() _ 
           On PartnerExchangeRates.Field(Of Date)("RateDate") Equals ContentExchangeRates.Field(Of Date)("EffectiveDate") _ 
           And PartnerExchangeRates.Field(Of String)("CurrencyCode") Equals ContentExchangeRates.Field(Of String)("ConvertCurrencyCode") _ 
           Into result = Group From m In result.DefaultIfEmpty _ 
                Select New With _ 
                { _ 
                .PartnerRateDate = m.Field(Of Date)("RateDate") _ 
                }).ToList 

Но я получаю следующую ошибку: Значение не может быть пустым. Имя параметра: строка

Я хочу быть в состоянии сделать левое внешнее соединение, которая будет извлекать только записи, которые не существует на столе PartnerExchangeRates, но я не знаю, что делать больше :(

Любая помощь приветствуется!

ответ

0

чтобы выполнить левое внешнее соединение, вам нужно сделать группу присоединиться и пройти через результаты группы присоединиться и использовать DefaultIfEmpty. Это будет перевести на левое внешнее соединение.

Dim query = 
    From cer In myDataset.Tables(0).AsEnumerable 
    Group Join per In PartnerDataSet.Tables(0).AsEnumerable 
     On New With 
     { 
      .Date = cer.Field(Of Date)("EffectiveDate"), 
      .Currency = cer.Field(Of String)("CurrencyCode") 
     } 
     Equals New With 
     { 
      .Date = per.Field(Of Date)("RateDate"), 
      .Currency = per.Field(Of String)("CurrencyCode") 
     } 
     Into pers = Group 
    From per in pers.DefaultIfEmpty 
    Where per Is Nothing 
    Select PartnerRateDate = per.Field(Of Date)("RateDate"), ... 
+0

Im получаю следующее сообщение об ошибке: Значение не может быть ноль. Имя параметра: строка –

0

Вы можете использовать Enumerable.Except(IEnumerable, IEnumerable, IEqualityComparer) метод:

Option Infer On 

Module Module1 

    Class RowComparer : Implements IEqualityComparer(Of DataRow) 

     Public Function Equals1(x As DataRow, y As DataRow) As Boolean Implements IEqualityComparer(Of DataRow).Equals 
      ' use .Equals for the DateTime and Is for the String 
      Return x(0).Equals(y(0)) AndAlso x(1) Is y(1) 
     End Function 

     Public Function GetHashCode1(obj As DataRow) As Integer Implements IEqualityComparer(Of DataRow).GetHashCode 
      Return obj(0).GetHashCode Xor obj(1).GetHashCode 
     End Function 

    End Class 

    Sub ShowDt(dt As DataTable) 
     For Each r As DataRow In dt.Rows 
      Console.WriteLine(CDate(r(0)).ToString("yyyy-MM-dd") & " " & CStr(r(1))) 
     Next 

     Console.WriteLine("-------------") 

    End Sub 

    Sub Main() 
     Dim dt(1) As DataTable 
     For i = 0 To 1 
      dt(i) = New DataTable 
      dt(i).Columns.Add(New DataColumn With {.ColumnName = "EffectiveDate", .DataType = Type.GetType("System.DateTime")}) 
      dt(i).Columns.Add(New DataColumn With {.ColumnName = "CurrencyCode", .DataType = Type.GetType("System.String")}) 
     Next 

     ' test data 
     For i = 0 To 1 
      For j = 1 To 10 
       Dim nr = dt(i).NewRow 
       nr("EffectiveDate") = New DateTime(2015, 1, j) 
       nr("CurrencyCode") = "USD" 
       dt(i).Rows.Add(nr) 
      Next 
     Next 

     ' remove a couple of rows from the second table 
     dt(1).Rows.RemoveAt(9) 
     dt(1).Rows.RemoveAt(2) 

     ShowDt(dt(0)) 
     ShowDt(dt(1)) 

     ' find the rows in dt(0) which are not in dt(1)... 
     Dim missings = (dt(0).AsEnumerable.Except(dt(1).AsEnumerable, New RowComparer())).CopyToDataTable() 

     ShowDt(missings) 

     Console.ReadLine() 

    End Sub 

End Module 

Но если это случится, что ваши данные поддаются хранятся в списках, ваш код может быть чище и более удобным для чтения:

Option Infer On 

Module Module1 

    Public Class DateAndCurrency 
     Public Property EffectiveDate As DateTime 
     Public Property CurrencyCode As String 

     Public Overrides Function ToString() As String 
      Return Me.EffectiveDate.ToString("yyyy-MM-dd") & " " & Me.CurrencyCode 
     End Function 

    End Class 

    Public Class DateAndCurrencyComparer : Implements IEqualityComparer(Of DateAndCurrency) 

     Public Function Equals1(x As DateAndCurrency, y As DateAndCurrency) As Boolean Implements IEqualityComparer(Of DateAndCurrency).Equals 
      Return x.CurrencyCode = y.CurrencyCode AndAlso x.EffectiveDate = y.EffectiveDate 
     End Function 

     Public Function GetHashCode1(obj As DateAndCurrency) As Integer Implements IEqualityComparer(Of DateAndCurrency).GetHashCode 
      Return obj.CurrencyCode.GetHashCode Xor obj.EffectiveDate.GetHashCode 
     End Function 

    End Class 

    Sub Main() 

     ' test data 
     Dim daccs As New List(Of List(Of DateAndCurrency)) 
     For i = 0 To 1 
      Dim dacc As New List(Of DateAndCurrency) 
      For j = 1 To 10 
       dacc.Add(New DateAndCurrency With {.EffectiveDate = New DateTime(2015, 1, j), .CurrencyCode = "USD"}) 
      Next 
      daccs.Add(dacc) 
     Next 

     ' remove a couple of rows from the second list 
     daccs(1).RemoveAt(9) 
     daccs(1).RemoveAt(2) 

     For i = 0 To 1 
      daccs(i).ForEach(Sub(x) Console.WriteLine(x.ToString())) 
      Console.WriteLine("-------------") 
     Next 

     ' find the items in daccs(0) which are not in daccs(1)... 
     Dim missings = daccs(0).Except(daccs(1), New DateAndCurrencyComparer()) 

     missings.ToList().ForEach(Sub(x) Console.WriteLine(x.ToString())) 
     Console.WriteLine("-------------") 

     Console.ReadLine() 

    End Sub 

End Module