请使用VB.Net解答!第一个问题:Linq语句中Group join与DefaultIfEmpty的结合,第二个问题:将自定义比较器作为参数时,没反应

望諸公 2020-08-06 08:18:43
Public Function Test2() As Boolean
Dim S(0) As String

'测试数据
Dim DT1 As New DataTable
DT1.TableName = "表1"

Dim DC1(0) As DataColumn
DC1(0) = New DataColumn
DC1(0).DataType = System.Type.GetType("System.String")
DC1(0).ColumnName = "主键1"
DT1.Columns.Add(DC1(0))
DT1.PrimaryKey = DC1

DC1(0) = New DataColumn
DC1(0).DataType = System.Type.GetType("System.String")
DC1(0).ColumnName = "列1" '取值于表:DT2 的主键
DT1.Columns.Add(DC1(0))
MsgBox(DT1.Columns.Count)

Dim DR1 As DataRow
Dim J As Integer
For J = 0 To 10 Step 1
DR1 = DT1.NewRow
DR1.BeginEdit()
DR1.Item("主键1") = "M1" & J
If J <= 5 Then DR1.Item("列1") = "F" & J '6个相等值,5个空值
DR1.EndEdit()
DT1.Rows.Add(DR1)
DR1.AcceptChanges()
Next J
MsgBox(DT1.Rows.Count)

Dim DT2 As New DataTable
DT2.TableName = "表2"

DC1(0) = New DataColumn
DC1(0).DataType = System.Type.GetType("System.String")
DC1(0).ColumnName = "主键2"
DT2.Columns.Add(DC1(0))
DT2.PrimaryKey = DC1

DC1(0) = New DataColumn
DC1(0).DataType = System.Type.GetType("System.String")
DC1(0).ColumnName = "显示列2"
DT2.Columns.Add(DC1(0))
MsgBox(DT2.Columns.Count)

For J = 0 To 10 Step 1
DR1 = DT2.NewRow
DR1.BeginEdit()
DR1.Item("主键2") = "F" & J
DR1.Item("显示列2") = "S" & J
DR1.EndEdit()
DT2.Rows.Add(DR1)
DR1.AcceptChanges()
Next J
MsgBox(DT2.Rows.Count)

'相等行测试
Dim Linq2 = From row1 As DataRow In DT1 Join row2 As DataRow In DT2 On row1.Item("列1") Equals row2.Item("主键2") Select row1, Show1 = row2.Item("显示列2")
For J = 0 To Linq2.Count - 1 Step 1
S(0) &= Chr(13) & Linq2(J).Show1
Next J
MsgBox(S(0)) '获得6行,正常


'第一个问题:Group1.Item("显示列2"),引发错误,原因是 Group1 未将对象引用设置到对象的实例。

Dim Linq1 = From row1 As DataRow In DT1 Group Join row2 As DataRow In DT2 On row1.Item("列1") Equals row2.Item("主键2") Into Group
From Group1 In Group.DefaultIfEmpty()
Select New Struct1 With {.DataRow1 = row1, .Count1 = 1, .FldName0 = "显示列2", .FldValue0 = IIf(Group1 Is Nothing, DBNull.Value, Group1.Item("显示列2")), .FldType0 = "System.String"}
MsgBox("左外联接行数 = " & Linq1.Count)


'自定义比较器
Dim ICompareStruct1Class As New ICompareStruct1
MsgBox(ICompareStruct1Class.Compare(Linq1(0), Linq1(1))) '测试正常

第二个问题:自定义比较器作为 OrderByDescending 或 OrderBy 的参数时,没有调动 Compare方法,没有排序

Linq1.OrderByDescending(Function(X) X, ICompareStruct1Class)

For J = 0 To Linq1.Count - 1 Step 1
S(0) &= Chr(13) & Linq1(J).DataRow1.Item(0)
Next J
MsgBox(S(0))

DT1.Dispose()
DT2.Dispose()
End Function


'自定义结构
Public Structure Struct1
Public DataRow1 As DataRow
Public Count1 As Integer '标记实际使用的 从1开始,最大是10的 参数个数

'字段值
Public FldValue0 As Object
Public FldValue1 As Object
Public FldValue2 As Object
Public FldValue3 As Object
Public FldValue4 As Object
Public FldValue5 As Object
Public FldValue6 As Object
Public FldValue7 As Object
Public FldValue8 As Object
Public FldValue9 As Object

'字段名称
Public FldName0 As String
Public FldName1 As String
Public FldName2 As String
Public FldName3 As String
Public FldName4 As String
Public FldName5 As String
Public FldName6 As String
Public FldName7 As String
Public FldName8 As String
Public FldName9 As String

'字段.数据类型
Public FldType0 As String
Public FldType1 As String
Public FldType2 As String
Public FldType3 As String
Public FldType4 As String
Public FldType5 As String
Public FldType6 As String
Public FldType7 As String
Public FldType8 As String
Public FldType9 As String
End Structure

'自定义比较器
Public Class ICompareStruct1
Implements IComparer(Of Struct1)
Implements IDisposable
'自定义结构:Struct1 的排序比较器

Private CompareValue1 As Integer
Public Sub New()
End Sub

Protected disposed As Boolean = False
Sub Dispose() Implements IDisposable.Dispose
Me.Dispose(True)
GC.SuppressFinalize(Me)
End Sub

Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposed Then
If disposing = True Then
End If
End If
Me.disposed = True
End Sub

Public Function Compare(X As Struct1, Y As Struct1) As Integer Implements IComparer(Of Struct1).Compare
Dim J As Integer
For J = 0 To X.Count1 - 1 Step 1
Select Case J
Case 0
CompareValue1 = CompareDetail(X.FldValue0, Y.FldValue0, X.FldType0)
Case 1
CompareValue1 = CompareDetail(X.FldValue1, Y.FldValue1, X.FldType1)
Case 2
CompareValue1 = CompareDetail(X.FldValue2, Y.FldValue2, X.FldType2)
Case 3
CompareValue1 = CompareDetail(X.FldValue3, Y.FldValue3, X.FldType3)
Case 4
CompareValue1 = CompareDetail(X.FldValue4, Y.FldValue4, X.FldType4)
Case 5
CompareValue1 = CompareDetail(X.FldValue5, Y.FldValue5, X.FldType5)
Case 6
CompareValue1 = CompareDetail(X.FldValue6, Y.FldValue6, X.FldType6)
Case 7
CompareValue1 = CompareDetail(X.FldValue7, Y.FldValue7, X.FldType7)
Case 8
CompareValue1 = CompareDetail(X.FldValue8, Y.FldValue8, X.FldType8)
Case 9
CompareValue1 = CompareDetail(X.FldValue9, Y.FldValue9, X.FldType9)
End Select
If CompareValue1 <> 0 Then Exit For
Next J

MsgBox(J & ", X.首值 = " & X.DataRow1.Item(0) & ",Y.首值 = " & Y.DataRow1.Item(0) & ", X值 = " & X.FldValue0 & ", Y值 = " & Y.FldValue0 & ", 数据类型 = " & X.FldType0 & ", 比较结果 = " & CompareValue1.ToString)

Return CompareValue1
End Function
End Class
...全文
2572 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
望諸公 2020-08-07
  • 打赏
  • 举报
回复
是的,运行通过了,谢谢两位!

另外,再请教,怎么用 BindingSource 来实现上述列表的排序,因为BindingSource 可以实现字符串排序,会比较方便:

'替换上面的排序方法,改用 BindingSource
Dim Bind1 As New BindingSource
Bind1.DataSource = Linq1
Bind1.Sort = "FldValue0 Asc" '提示错误: 没有这个属性
S(0) = ""
For J = 0 To Bind1.Count - 1 Step 1
S(0) &= Chr(13) & Bind1(J).DataRow1.Item(0)
Next J
MsgBox(S(0))
hztltgg 2020-08-07
  • 打赏
  • 举报
回复
Linq2前面已经定义了,要换个名字 DIM LinqResult = Linq1.OrderByDescending(Function(X) X, ICompareStruct1Class) 排序返回的是个新结果,不是在原来的linq1集合上排序的,orderby语句只是定义了怎么排,要在返回集合的时候才执行,但你又没有变量去接,就被程序给忽略了 当然显示的也要改下变量 For J = 0 To linqresult.Count - 1 Step 1 S(0) &= Chr(13) & linqresult(J).DataRow1.Item(0).ToString Next J MsgBox(S(0)) 这边试了是可以的
github_36000833 2020-08-07
  • 打赏
  • 举报
回复
string a = "Hello"; a.SubString(2); // 并不会改变a,而是返回一个子字符串。 因此,要 var b = a.SubString(2); Linq查询是懒惰执行的, 如果你没有Linq2,排序同样没有执行的。
github_36000833 2020-08-07
  • 打赏
  • 举报
回复
引用 4 楼 望諸公 的回复:
[quote=引用 3 楼 github_36000833 的回复:]DIM Linq2 = Linq1.OrderByDescending(Function(X) X, ICompareStruct1Class)
结果没有排序,Compare也没有被触发,不行[/quote] 你用Linq2了吗?
github_36000833 2020-08-07
  • 打赏
  • 举报
回复
:( 收到你回复的通知。 看不到回复的帖子。
望諸公 2020-08-07
  • 打赏
  • 举报
回复
引用 3 楼 github_36000833 的回复:
DIM Linq2 = Linq1.OrderByDescending(Function(X) X, ICompareStruct1Class)


结果没有排序,Compare也没有被触发,不行
github_36000833 2020-08-07
  • 打赏
  • 举报
回复
DIM Linq2 = Linq1.OrderByDescending(Function(X) X, ICompareStruct1Class)
hztltgg 2020-08-07
  • 打赏
  • 举报
回复
引用
若要支持排序,基础列表必须实现 IBindingList 或 IBindingListView 接口。 此功能可通过 SupportsSorting 属性进行查询。 当 trueSupportsAdvancedSorting 属性时,多列排序将可用。 设置 Sort 属性将更改内部列表,具体取决于其类型: 如果列表的类型为 IBindingList,则将在内部列表中设置 IBindingList.SortProperty 和 IBindingList.SortDirection 属性。 如果列表的类型为 IBindingListView,则将设置 IBindingListView.SortDescriptions 属性。 仅当不 null排序字符串时,内部列表的排序属性才会更改。 此属性的 get 访问器不会检索内部列表的排序值;相反,它将返回 set 访问器的值。 数据源更改时,Sort 属性的值将保持不变。
======================== 用 BindingSource的Sort 也是要把集合处理成可排序的集合才行,既然已经用linq了,直接通过linq排序更方便吧
望諸公 2020-08-06
  • 打赏
  • 举报
回复
第一个问题已解决:From Group1 In Group.DefaultIfEmpty(DT2.NewRow)
有哪位能尽快帮我处理第二个问题吗?分数不变。本来就是要解决第二个问题,第一个问题是半路杀出来的。
望諸公 2020-08-06
  • 打赏
  • 举报
回复
补充程序 CompareDetail:

Public Module CompareX
'字段比较
Public Function CompareDetail(X As Object, Y As Object, FieldType1 As String) As Integer
Select Case FieldType1
Case "System.Boolean"
If X = Y Then
Return 0
Else
If X = True Then Return -1 Else Return 1
End If
Case "System.DateTime"
Select Case DateAndTime.DateDiff(DateInterval.Second, X, Y) '函数自动处理 Nothing的值
Case 0
Return 0
Case < 0
Return 1
Case Else
Return -1
End Select
Case "System.String"
Return String.Compare(X.ToString, Y.ToString, StringComparison.OrdinalIgnoreCase)
Case Else '统归为数值类
If IsDBNull(X) = True Then
If IsDBNull(Y) = True Then Return 0 Else Return -1
Else
If IsDBNull(Y) = True Then
Return 1
Else
Select Case X
Case < Y
Return -1
Case Y
Return 0
Case Else
Return 1
End Select
End If
End If
End Select
End Function
End Module

8,497

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 LINQ
社区管理员
  • LINQ
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧