persistence/DD.Persistence.Client/TimestampedSetMapper.cs

136 lines
3.7 KiB
C#
Raw Normal View History

using DD.Persistence.Models;
using System.Collections.Concurrent;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.Json;
namespace DD.Persistence.Client;
internal abstract class TimestampedSetMapperBase
{
public abstract object Map(TimestampedValuesDto data);
}
internal class TimestampedSetMapper<T> : TimestampedSetMapperBase
{
private readonly Type entityType = typeof(T);
public Guid IdDiscriminator { get; }
private readonly ConcurrentDictionary<string, PropertyInfo?> PropertyCache = new();
public TimestampedSetMapper(Guid idDiscriminator)
{
IdDiscriminator = idDiscriminator;
}
public override object Map(TimestampedValuesDto data)
{
return DeserializeTimeStampedData(data)!;
}
public T DeserializeTimeStampedData(TimestampedValuesDto data)
{
if (entityType.IsValueType)
return MapStruct(data);
else
return MapClass(data);
}
private T MapClass(TimestampedValuesDto data)
{
var entity = (T)RuntimeHelpers.GetUninitializedObject(typeof(T));
foreach (var (propertyName, value) in data.Values)
{
if (value is JsonElement jsonElement)
SetPropertyValueFromJson(ref entity, propertyName, jsonElement);
}
SetPropertyValue(ref entity, "Timestamp", data.Timestamp);
return entity;
}
private T MapStruct(TimestampedValuesDto data)
{
var entity = Activator.CreateInstance<T>();
object boxedEntity = entity!;
foreach (var (propertyName, value) in data.Values)
{
if (value is JsonElement jsonElement)
SetPropertyValueForStructFromJson(ref boxedEntity, propertyName, jsonElement);
}
SetPropertyValueForStruct(ref boxedEntity, "Timestamp", data.Timestamp);
return (T)boxedEntity;
}
private void SetPropertyValueForStructFromJson(ref object entity, string propertyName, JsonElement element)
{
var property = GetPropertyInfo(propertyName);
if (property is null)
return;
try
{
var value = element.Deserialize(property.PropertyType);
property.SetValue(entity, value);
}
catch (Exception ex)
{
}
}
private void SetPropertyValueForStruct(ref object entity, string propertyName, object value)
{
var property = GetPropertyInfo(propertyName);
if (property is null)
return;
try
{
var convertedValue = Convert.ChangeType(value, property.PropertyType);
property.SetValue(entity, convertedValue);
}
catch (Exception ex)
{
}
}
private void SetPropertyValueFromJson(ref T entity, string propertyName, JsonElement jsonElement)
{
var property = GetPropertyInfo(propertyName);
if (property is null)
return;
try
{
var value = jsonElement.Deserialize(property.PropertyType);
property.SetValue(entity, value);
}
catch (Exception ex)
{
}
}
private void SetPropertyValue(ref T entity, string propertyName, object value)
{
var property = GetPropertyInfo(propertyName);
if (property is null)
return;
try
{
var convertedValue = Convert.ChangeType(value, property.PropertyType);
property.SetValue(entity, convertedValue);
}
catch (Exception ex)
{
}
}
private PropertyInfo? GetPropertyInfo(string propertyName)
{
return PropertyCache.GetOrAdd(propertyName, name => entityType.GetProperty(name));
}
}