src/Mapping/DataMapper.psm1
|
using namespace System.Collections using namespace System.ComponentModel.DataAnnotations.Schema using namespace System.Diagnostics.CodeAnalysis using namespace System.Reflection <# .SYNOPSIS Maps data records to entity objects. #> class DataMapper { <# .SYNOPSIS The property maps, keyed by type. #> hidden static [hashtable] $PropertyMaps = @{} <# .SYNOPSIS Creates a new object of a given type from the specified data record. .PARAMETER Type The object type. .PARAMETER Record A data record providing the properties to be set on the created object. .OUTPUTS The newly created object. #> [SuppressMessage("PSUseDeclaredVarsMoreThanAssignments", "")] [object] CreateInstance([type] $Type, [System.Data.IDataRecord] $Record) { $properties = @{} for ($index = 0; $index -lt $Record.FieldCount; $index++) { $key = $Record.GetName($index) $properties.$key = $Record.IsDBNull($index) ? $null : $Record.GetValue($index) } return $discard = switch ($Type) { ([hashtable]) { $properties; break } ([psobject]) { [pscustomobject] $properties; break } default { $this.CreateInstance($Type, $properties) } } } <# .SYNOPSIS Creates a new object of a given type from the specified hash table. .PARAMETER Type The object type. .PARAMETER Properties A hash table providing the properties to be set on the created object. .OUTPUTS The newly created object. #> [object] CreateInstance([type] $Type, [hashtable] $Properties) { $culture = [cultureinfo]::InvariantCulture $object = $Type::new() $propertyMap = $this.GetPropertyMap($Type) foreach ($key in $Properties.Keys.Where{ $_ -in $propertyMap.Keys }) { $propertyInfo = $propertyMap.$key $propertyType = [Nullable]::GetUnderlyingType($propertyInfo.PropertyType) ?? $propertyInfo.PropertyType $value = $Properties.$key $object.$($propertyInfo.Name) = switch ($true) { ($null -eq $value) { $null; break } ($propertyType.IsEnum) { [Enum]::ToObject($propertyType, $value); break } default { [Convert]::ChangeType($value, $propertyType, $culture) } } } return $object } <# .SYNOPSIS Creates new objects of a given type from the specified data reader. .PARAMETER Type The object type. .PARAMETER Reader A data reader providing the properties to be set on the created objects. .OUTPUTS An array of newly created objects. #> [object[]] CreateInstances([type] $Type, [System.Data.IDataReader] $Reader) { $list = [ArrayList]::new() while ($Reader.Read()) { $list.Add($this.CreateInstance($Type, $Reader)) } $Reader.Close() return $list.ToArray() } <# .SYNOPSIS Retrives a hash table of mapped properties of the specified type. .PARAMETER Type The type to inspect. .OUTPUTS The hash table of mapped properties of the specified type. #> [hashtable] GetPropertyMap([type] $Type) { if ($Type -in [DataMapper]::PropertyMaps.Keys) { return [DataMapper]::PropertyMaps.$Type } $propertyMap = @{} $propertyInfos = $Type.GetProperties([BindingFlags]::Instance -bor [BindingFlags]::Public) foreach ($propertyInfo in $propertyInfos.Where{ $_.CanWrite -and (-not [Attribute]::IsDefined($_, ([NotMappedAttribute])))}) { $column = [Attribute]::GetCustomAttribute($propertyInfo, ([ColumnAttribute])) $propertyMap.$($column ? $column.Name : $propertyInfo.Name) = $propertyInfo } return [DataMapper]::PropertyMaps.$Type = $propertyMap } } |