树和自联表(三)

Author:水如烟  

实现。

再次思考尝试后,做成这样:

具体使用时,要实现这个类SinceLinkItemBase。

SinceLinkItemBase.vb

 

Namespace  LzmTW.uSystem.uCollection.SinceLink

    
< Serializable() >  _
    
Public   MustInherit   Class  SinceLinkItemBase( Of  T_ID_DataType)

        
Private  gName  As   String
        
Friend  gCode  As   String

        
< NonSerialized() >  _
        
Private  gCodeInformation  As  SinceLinkCodeInformation

        
Sub   New ()
        
End Sub

        
Sub   New ( ByVal  code  As   String ByVal  name  As   String )
            gName 
=  name
            gCode 
=  code
        
End Sub

        
Public   ReadOnly   Property  Code()  As   String
            
Get
                
Return  gCode
            
End   Get
        
End Property

        
Public   Property  Name()  As   String
            
Get
                
Return  gName
            
End   Get
            
Set ( ByVal  value  As   String )
                gName 
=  value
            
End   Set
        
End Property

        
Friend   Sub  UpdateInformations( ByVal  codeFormat  As   String )
            gCodeInformation 
=   New  SinceLinkCodeInformation(codeFormat)
            gCodeInformation.SetCode(gCode)
        
End Sub

        
Friend   Function  GetLevel()  As   Integer
            
Return  gCodeInformation.Level
        
End Function

        
Friend   Function  GetID()  As  T_ID_DataType
            
Return   CType (System.Convert.ChangeType(gCodeInformation.ID,  GetType (T_ID_DataType)), T_ID_DataType)
        
End Function

        
Friend   Function  GetParentID()  As  T_ID_DataType
            
Return   CType (System.Convert.ChangeType(gCodeInformation.ParentID,  GetType (T_ID_DataType)), T_ID_DataType)
        
End Function

        
Friend   Function  GetParentKey()  As   String
            
Return  gCodeInformation.ParentKey
        
End Function

        
Friend   Function  GetLevels()  As   Integer
            
Return  gCodeInformation.Levels
        
End Function

        
Public   Function  Clone()  As  SinceLinkItemBase( Of  T_ID_DataType)
            
Return  uSystem.uRuntime.uSerialization.SerializeHelper.Clone( Of  SinceLinkItemBase( Of  T_ID_DataType))( Me )
        
End Function

    
End Class

End Namespace

 

Namespace  LzmTW.uSystem.uCollection.SinceLink
    
Friend   Class  SinceLinkCodeInformation
        
Private  gCode  As   String
        
Private  gCodeFormat  As   String   =   " 00,00,00 "

        
' 当前层级
         Private  gLevel  As   Integer
        
' 层数
         Private  gLevels  As   Integer

        
Private  gID  As   String
        
Private  gParentID  As   String

        
' 代码的各组ID位数
         Private  gIDLengths()  As   Integer

        
Private  gParentKey  As   String

        
Sub   New ( ByVal  codeFormat  As   String )
            gCodeFormat 
=  codeFormat

            
Dim  mIDArray()  As   String   =  gCodeFormat.Split( " , " c)
            
ReDim  gIDLengths(mIDArray.Length  -   1 )
            
For  i  As   Integer   =   0   To  mIDArray.Length  -   1
                gIDLengths(i) 
=  mIDArray(i).Length
            
Next

            gLevels 
=  gIDLengths.Length
        
End Sub

        
Public   ReadOnly   Property  Level()  As   Integer
            
Get
                
Return  gLevel
            
End   Get
        
End Property

        
Public   ReadOnly   Property  Levels()  As   Integer
            
Get
                
Return  gLevels
            
End   Get
        
End Property

        
Public   ReadOnly   Property  ID()  As   String
            
Get
                
Return  gID
            
End   Get
        
End Property

        
Public   ReadOnly   Property  ParentID()  As   String
            
Get
                
Return  gParentID
            
End   Get
        
End Property

        
Public   ReadOnly   Property  ParentKey()  As   String
            
Get
                
Return  gParentKey
            
End   Get
        
End Property


        
Public   Sub  SetCode( ByVal  code  As   String )
            gCode 
=  code
            GetIDInfos()
        
End Sub

        
Private   Sub  GetIDInfos()
            
Dim  tmpIDInfos(gLevels  -   1 As   String

            
Dim  mCurrentIndex  As   Integer   =   0
            
For  i  As   Integer   =   0   To  gLevels  -   1
                tmpIDInfos(i) 
=  gCode.Substring(mCurrentIndex, gIDLengths(i))
                mCurrentIndex 
+=  gIDLengths(i)
            
Next

            
For  i  As   Integer   =  gLevels  -   1   To   0   Step   - 1
                
If   Not  System.Text.RegularExpressions.Regex.IsMatch(tmpIDInfos(i),  " ^0+$ " Then
                    gLevel 
=  i  +   1
                    gID 
=  tmpIDInfos(i)
                    
If  i  =   0   Then
                        gParentID 
=   New   String ( " 0 " c, gIDLengths( 0 ))
                        gParentKey 
=   New   String ( " 0 " c, gIDLengths( 0 ))
                    
Else
                        gParentID 
=  tmpIDInfos(i  -   1 )

                        
For  k  As   Integer   =   0   To  i  -   1
                            gParentKey 
+=  tmpIDInfos(k)
                        
Next
                    
End   If

                    
Exit   For
                
End   If
            
Next

        
End Sub
    
End Class
End Namespace

数据集合,SinceLinkItemCollection.vb

 

Namespace  LzmTW.uSystem.uCollection.SinceLink

    
< Serializable() >  _
    
Public   Class  SinceLinkItemCollection( Of  T_ID_DataType, T  As  SinceLinkItemBase( Of  T_ID_DataType))
        
Inherits  System.Collections.ObjectModel.Collection( Of  T)

        
< NonSerialized() >  _
        
Private  gNode  As  Node( Of  T)

        
Private  gCodeFormat  As   String

        
Sub   New ()
        
End Sub

        
' '' <param name="codeFormat">形如00,000,0000</param>
         Sub   New ( ByVal  codeFormat  As   String )
            gCodeFormat 
=  codeFormat
        
End Sub

        
Public   ReadOnly   Property  Node()  As  Node( Of  T)
            
Get
                
If  gNode  Is   Nothing   Then
                    
Me .RefleshNode()
                
End   If
                
Return  gNode
            
End   Get
        
End Property

        
Public   Shadows   Function  Add( ByVal  code  As   String ByVal  name  As   String As  T
            
Dim  mItem  As  T  =   CType (System.Activator.CreateInstance( GetType (T),  New   Object () {code, name}), T)
            
Me .Add(mItem)

            
Return  mItem
        
End Function

        
Public   Shadows   Sub  Add( ByVal  items  As  T())
            
For   Each  item  As  T  In  items
                Add(item)
            
Next
        
End Sub

        
Public   Shadows   Function  Add( ByVal  item  As  T)  As  T
            item.UpdateInformations(gCodeFormat)

            
MyBase .Add(item)

            
Return  item
        
End Function

        
Public   Sub  AppendFromSinceLinkTable( ByVal  sinceLinkTable  As  DataTable)
            
Dim  mSinceLinkTable  As   New  SinceLinkTable( Of  T_ID_DataType, T)

            mSinceLinkTable.Input(sinceLinkTable)
            gCodeFormat 
=  mSinceLinkTable.CodeFormat

            Add(mSinceLinkTable.Items)
        
End Sub

        
Public   Sub  RefleshNode()
            gNode 
=  GetNode()
        
End Sub

        
Private   Function  GetNode()  As  Node( Of  T)
            
If   Me .Count  =   0   Then   Return   Nothing

            
Dim  mItem  As  T  =   CType (System.Activator.CreateInstance( GetType (T),  New   Object () { New   String ( " 0 " c, gCodeFormat.Replace( " , " c,  "" ).Length),  " Root " }), T)
            mItem.UpdateInformations(gCodeFormat)

            
Dim  mNode  As   New  Node( Of  T)(mItem)

            
Dim  mCurrentNode  As  Node( Of  T)
            
' 加首级
             For   Each  item  As  T  In   Me .Items

                
If  item.GetLevel  =   1   Then
                    mCurrentNode 
=  mNode.Nodes.Add(item)

                    
' 加子级
                    AppendItem(mCurrentNode)
                
End   If

            
Next

            
Return  mNode
        
End Function

        
Private   Sub  AppendItem( ByRef  node  As  Node( Of  T))
            
Dim  mCurrentNode  As  Node( Of  T)
            
For   Each  item  As  T  In  GetChildItem(node.Item)
                mCurrentNode 
=  node.Nodes.Add(item)

                AppendItem(mCurrentNode)
            
Next

        
End Sub

        
Public   Function  GetChildItem( ByVal  item  As  T)  As  System.Collections.ObjectModel.Collection( Of  T)
            
Dim  mList  As   New  System.Collections.ObjectModel.Collection( Of  T)

            
If  item.GetLevel  =  item.GetLevels  Then   Return  mList
            
For   Each  value  As  T  In   Me .Items
                
If  item.Code.StartsWith(value.GetParentKey)  AndAlso  value.GetParentID.Equals(item.GetID)  AndAlso  item.GetLevel  =  value.GetLevel  -   1   Then
                    mList.Add(value)
                
End   If
            
Next

            
Return  mList
        
End Function

    
End Class

End Namespace

 

Namespace  LzmTW.uSystem.uCollection.SinceLink

    
Friend   Class  SinceLinkTable( Of  T_ID_DataType, T  As  SinceLinkItemBase( Of  T_ID_DataType))
        
Private  gList  As   New  ArrayList
        
Private  gItems  As  T()
        
Private  gDataTable  As  DataTable

        
Private  gFilterFormat  As   String
        
Private  gCodeFormat  As   String
        
Private  gNode  As  Node( Of  T)

        
Private  gLevelLengths( 0 As   Integer

        
Public   ReadOnly   Property  Items()  As  T()
            
Get
                
Return  gItems
            
End   Get
        
End Property

        
Public   ReadOnly   Property  CodeFormat()  As   String
            
Get
                
Return  gCodeFormat
            
End   Get
        
End Property

        
Sub   New ()
            
If   GetType (T).GetMethod( " GetID " , Reflection.BindingFlags.NonPublic  Or  Reflection.BindingFlags.Instance).ReturnType  Is   GetType ( String Then
                gFilterFormat 
=   " ParentID = '{0}' "
            
Else
                gFilterFormat 
=   " ParentID = {0} "
            
End   If
        
End Sub

        
Public   Sub   Input ( ByVal  table  As  DataTable)
            
If   Not   Me .IsSinceLinkTable(table)  Then   Throw   New  Exception( " 表不是自联表.若是,需有ID、ParentID字段和Name字段. " )
            
If  table.Rows.Count  =   0   Then   Throw   New  Exception( " 无数据 " )

            
Me .Copy(table)

            
Me .CreateNode()

            
Me .UpdateCode()

            
Me .Clear()

        
End Sub

        
Private   Function  IsSinceLinkTable( ByVal  table  As  DataTable)  As   Boolean
            
With  table.Columns
                
If  .Contains( " ID " Then
                    
If  .Contains( " ParentID " Then
                        
Return  .Contains( " Name " )
                    
End   If
                
End   If
            
End   With

            
Return   False
        
End Function

        
Private   Sub  Copy( ByVal  table  As  DataTable)
            gDataTable 
=  table.Clone
            gDataTable.Load(table.CreateDataReader)
            gDataTable.AcceptChanges()
        
End Sub

        
Private   Sub  CreateNode()

            
Dim  mMainView  As  DataView  =   New  DataView(gDataTable,  Nothing " ID " , DataViewRowState.CurrentRows)
            
If   Not  mMainView.Item( 0 ).Item( " Name " ).ToString.ToLower.Equals( " root " Then
                
Throw   New  Exception( " 首位ID数据行的Name字段须有Root值示为根 " )
            
End   If

            
Dim  mItem  As  T  =   CType (System.Activator.CreateInstance( GetType (T),  New   Object () { "" " Root " }), T)
            gNode 
=   New  Node( Of  T)(mItem)

            
Dim  mLevels  As   Integer   =   0
            AppendNode(mMainView.Item(
0 ).Item( " ID " ), gNode, gLevelLengths, mLevels)

            
Dim  tmpFormat(mLevels  -   1 As   String
            
For  i  As   Integer   =   0   To  mLevels  -   1
                gLevelLengths(i) 
=  gLevelLengths(i).ToString.Length
                tmpFormat(i) 
=   New   String ( " 0 " c, gLevelLengths(i))
            
Next

            gCodeFormat 
=   String .Join( " , " , tmpFormat)
        
End Sub

        
Private   Sub  AppendNode( ByVal  ParentID  As   Object ByVal  node  As  Node( Of  T),  ByRef  levelengths()  As   Integer ByRef  levels  As   Integer )
            
Dim  mDataView  As  DataView  =  GetDataView(ParentID)

            
Dim  mCount  As   Integer   =  mDataView.Count
            
If  mCount  =   0   Then   Exit Sub

            
Dim  mNode  As  Node( Of  T)

            
For   Each  rowView  As  DataRowView  In  mDataView
                mNode 
=  node.Nodes.Add(CreateItem(rowView))

                AppendNode(rowView.Item(
" ID " ), mNode, levelengths, levels)
            
Next

            
If  mNode.Level  >  node.Level  Then
                
If  mNode.Level  >  levels  Then
                    levels 
=  mNode.Level
                    
ReDim   Preserve  levelengths(levels  -   1 )
                    levelengths(mNode.Level 
-   1 =  mCount
                
Else
                    levelengths(mNode.Level 
-   1 =  Math.Max(mCount, levelengths(mNode.Level  -   1 ))
                
End   If
            
Else
                levelengths(mNode.Level 
-   1 =  Math.Max(mCount, levelengths(mNode.Level  -   1 ))
            
End   If

        
End Sub

        
Private   Function  GetDataView( ByVal  ParentID  As   Object As  DataView
            
Return   New  DataView(gDataTable,  String .Format(gFilterFormat, ParentID),  " ID " , DataViewRowState.CurrentRows)
        
End Function

        
Private   Function  CreateItem( ByVal  rowView  As  DataRowView)  As  T
            
Dim  mItem  As  T
            mItem 
=   CType (System.Activator.CreateInstance( GetType (T)), T)

            
For   Each  p  As  Reflection.PropertyInfo  In   GetType (T).GetProperties
                
If  p.CanWrite  Then
                    
If  rowView.DataView.Table.Columns.Contains(p.Name)  Then
                        p.SetValue(mItem, rowView.Item(p.Name), 
Nothing )
                    
End   If
                
End   If
            
Next

            
Return  mItem
        
End Function

        
Private   Sub  UpdateCode()
            gNode.Item.gCode 
=   New   String ( " 0 " c, RightLength( 0 ))
            UpdateCode(gNode)

            
ReDim  gItems(gList.Count  -   1 )
            gList.CopyTo(gItems)
        
End Sub

        
Private   Sub  UpdateCode( ByVal  node  As  LzmTW.uSystem.uCollection.Node( Of  T))
            
For   Each  n  As  Node( Of  T)  In  node.Nodes
                n.Item.gCode 
=  GetCode(n.Parent.Item.Code, n.Level, n.Index)
                gList.Add(n.Item)

                UpdateCode(n)
            
Next
        
End Sub

        
Private   Function  GetCode( ByVal  parentCode  As   String ByVal  level  As   Integer ByVal  index  As   Integer As   String
            
Return   String .Concat(parentCode.Substring( 0 , LeftLength(level)), (index  +   1 ).ToString.PadRight(RightLength(level),  " 0 " c))
        
End Function

        
Private   Function  LeftLength( ByVal  level  As   Integer As   Integer
            
Dim  tmp  As   Integer   =   0
            
For  i  As   Integer   =   0   To  level  -   1
                tmp 
+=  gLevelLengths(i)
            
Next
            
Return  tmp  -   1
        
End Function

        
Private   Function  RightLength( ByVal  level  As   Integer As   Integer
            
Dim  tmp  As   Integer   =   0
            
For  i  As   Integer   =  level  To  gLevelLengths.Length  -   1
                tmp 
+=  gLevelLengths(i)
            
Next
            
Return  tmp  +   1
        
End Function

        
Private   Sub  Clear()
            gDataTable.Clear()
            gDataTable.Dispose()

            gNode.Nodes.Clear()

            gList.Clear()

            gLevelLengths 
=   Nothing
        
End Sub
    
End Class

End Namespace

重新利用以前的方法,取网上的行政区划码数据,来测试。

测试代码,其中的gRegionalDatas由上面的方法给出,在此不再列此部分代码。

实现类SinceLinkItemBase

Public   Class  RegionalCodeItem
    
Inherits  LzmTW.uSystem.uCollection.SinceLink.SinceLinkItemBase( Of   String )

    
Sub   New ( ByVal  code  As   String ByVal  name  As   String )
        
MyBase .New(code, name)
    
End Sub

End Class

输出到界面:

 

     Public  gRegionalDatas  As  DataTable

    
Private   Sub  Button1_Click( ByVal  sender  As  System.Object,  ByVal  e  As  System.EventArgs)  Handles  Button1.Click

        
Dim  mCollection  As   New  LzmTW.uSystem.uCollection.SinceLink.SinceLinkItemCollection( Of   String , RegionalCodeItem)( " 00,00,00 " )

        Console.WriteLine(gRegionalDatas.Rows.Count)

        
For   Each  row  As  DataRow  In  gRegionalDatas.Rows
            
With  row
                mCollection.Add(.Item(
0 ).ToString, .Item( 1 ).ToString)
            
End   With
        
Next

        
Dim  mNode  As  LzmTW.uSystem.uCollection.Node( Of  RegionalCodeItem)  =  mCollection.Node
        Console.WriteLine(mNode.GetNodeCount(
True ))

        
Dim  tmpTable  As  DataTable  =  mNode.ConvertToDataTable( True )
        
Me .DataGridView1.DataSource  =  tmpTable
        Console.WriteLine(tmpTable.Rows.Count)

        
Me .TreeView1.Nodes.Clear()
        
Me .TreeView1.Nodes.Add(mNode.ConvertToTreeNode( " Name " True ))
    
End Sub

效果(已修改,大致如此,只是那些字段没了):

这个应用蛮广,后面的写的会多次用到。边用边完善。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值