Files
tsUtilidades/Extensiones/IEnumerable.vb
2025-05-29 17:58:18 +02:00

151 lines
5.9 KiB
VB.net

Imports System.Runtime.CompilerServices
Imports System.Reflection
Imports System.Data
Namespace Extensiones
Public Module IEnumerableExtensions
<Extension()>
Public Function CopyToDataTable(Of T)(ByVal source As IEnumerable(Of T)) As DataTable
Return New ObjectShredder(Of T)().Shred(source, Nothing, Nothing)
End Function
<Extension()>
Public Function CopyToDataTable(Of T)(ByVal source As IEnumerable(Of T), ByVal table As DataTable, ByVal options As LoadOption?) As DataTable
Return New ObjectShredder(Of T)().Shred(source, table, options)
End Function
End Module
End Namespace
Public Class ObjectShredder(Of T)
Private _fi As FieldInfo()
Private _pi As PropertyInfo()
Private _ordinalMap As Dictionary(Of String, Integer)
Private _type As Type
Public Sub New()
_type = GetType(T)
_fi = _type.GetFields()
_pi = _type.GetProperties.Where(Function(x) Not (x.PropertyType.Name.Contains("EntityReference") OrElse x.PropertyType.Name.Contains("EntityCollection") OrElse x.PropertyType.Name.Contains("EntityState") OrElse x.PropertyType.Name.Contains("EntityKey") OrElse x.PropertyType.BaseType.Name = "EntityObject")).ToArray
_ordinalMap = New Dictionary(Of String, Integer)()
End Sub
Public Function Shred(ByVal source As IEnumerable(Of T), ByVal table As DataTable, ByVal options As LoadOption?) As DataTable
If GetType(T).IsPrimitive Then
Return ShredPrimitive(source, table, options)
End If
If table Is Nothing Then
table = New DataTable(GetType(T).Name)
End If
table = ExtendTable(table, GetType(T))
table.BeginLoadData()
Using e As IEnumerator(Of T) = source.GetEnumerator()
While e.MoveNext()
If options IsNot Nothing Then
table.LoadDataRow(ShredObject(table, e.Current), CType(options, LoadOption))
Else
table.LoadDataRow(ShredObject(table, e.Current), True)
End If
End While
End Using
table.EndLoadData()
Return table
End Function
Public Function ShredPrimitive(ByVal source As IEnumerable(Of T), ByVal table As DataTable, ByVal options As LoadOption?) As DataTable
If table Is Nothing Then
table = New DataTable(GetType(T).Name)
End If
If Not table.Columns.Contains("Value") Then
table.Columns.Add("Value", GetType(T))
End If
table.BeginLoadData()
Using e As IEnumerator(Of T) = source.GetEnumerator()
Dim values As Object() = New Object(table.Columns.Count - 1) {}
While e.MoveNext()
values(table.Columns("Value").Ordinal) = e.Current
If options IsNot Nothing Then
table.LoadDataRow(values, CType(options, LoadOption))
Else
table.LoadDataRow(values, True)
End If
End While
End Using
table.EndLoadData()
Return table
End Function
Public Function ExtendTable(ByVal table As DataTable, ByVal type As Type) As DataTable
For Each f As FieldInfo In type.GetFields()
If Not _ordinalMap.ContainsKey(f.Name) Then
Dim dc As DataColumn = If(table.Columns.Contains(f.Name), table.Columns(f.Name), table.Columns.Add(f.Name, f.FieldType))
_ordinalMap.Add(f.Name, dc.Ordinal)
End If
Next
Dim Propiedades = type.GetProperties.Where(Function(x) Not (x.PropertyType.Name.Contains("EntityReference") OrElse x.PropertyType.Name.Contains("EntityCollection") OrElse x.PropertyType.Name.Contains("EntityState") OrElse x.PropertyType.Name.Contains("EntityKey") OrElse x.PropertyType.BaseType.Name = "EntityObject"))
For Each p As PropertyInfo In Propiedades
If Not _ordinalMap.ContainsKey(p.Name) Then
Dim propiedad = p.PropertyType
If propiedad Is GetType(Integer?) Then
propiedad = GetType(Integer)
ElseIf propiedad Is GetType(Double?) Then
propiedad = GetType(Double)
ElseIf propiedad Is GetType(Long?) Then
propiedad = GetType(Long)
ElseIf propiedad Is GetType(Boolean?) Then
propiedad = GetType(Boolean)
ElseIf propiedad Is GetType(DateTime?) Then
propiedad = GetType(DateTime)
ElseIf propiedad Is GetType(Date?) Then
propiedad = GetType(Date)
End If
Dim dc As DataColumn = If(table.Columns.Contains(p.Name), table.Columns(p.Name), table.Columns.Add(p.Name, propiedad))
_ordinalMap.Add(p.Name, dc.Ordinal)
End If
Next
Return table
End Function
Public Function ShredObject(ByVal table As DataTable, ByVal instance As T) As Object()
Dim fi As FieldInfo() = _fi
Dim pi As PropertyInfo() = _pi
If instance.[GetType]() <> GetType(T) Then
ExtendTable(table, instance.[GetType]())
fi = instance.[GetType]().GetFields()
pi = instance.[GetType]().GetProperties.Where(Function(x) Not (x.PropertyType.Name.Contains("EntityReference") OrElse x.PropertyType.Name.Contains("EntityCollection") OrElse x.PropertyType.Name.Contains("EntityState") OrElse x.PropertyType.Name.Contains("EntityKey") OrElse x.PropertyType.BaseType.Name = "EntityObject")).ToArray
End If
Dim values As Object() = New Object(table.Columns.Count - 1) {}
For Each f As FieldInfo In fi
values(_ordinalMap(f.Name)) = f.GetValue(instance)
Next
For Each p As PropertyInfo In pi
values(_ordinalMap(p.Name)) = p.GetValue(instance, Nothing)
Next
Return values
End Function
End Class