Somewhere in the internet I found below class which I am using to convert Expression<Func<T, bool>>
from DTO to Domain:
public class EvaluateVariableVisitor<TEntity, TDto> : ExpressionVisitor
{
private readonly ParameterExpression _dtoParameter;
private readonly ParameterExpression _entityParameter;
private readonly IMapper _mapper;
public EvaluateVariableVisitor()
{
_entityParameter = Expression.Parameter(typeof(TEntity));
_dtoParameter = Expression.Parameter(typeof(TDto));
_mapper = AutoMapperConfig.Initialize();
}
protected override Expression VisitMember(MemberExpression node)
{
try
{
//change dto to entity type.
if (node.Expression.Type == _dtoParameter.Type)
{
var reducedExpression = Visit(node.Expression);
//TypeMap typeMap = Mapper.Configuration.FindTypeMapFor<TDto, TEntity>();
TypeMap typeMap = _mapper.ConfigurationProvider.FindTypeMapFor<TDto, TEntity>();
//find the correct name of the property in the destination object by using the name of the source objekt
string destinationPropertyName = typeMap.GetPropertyMaps() //GetCustomPropertyMaps()
.Where(propertyMap => propertyMap.SourceMember.Name == node.Member.Name)
.Select(propertyMap => propertyMap.DestinationProperty.Name).FirstOrDefault();
//find the correct name of the property in the destination object by using the name of the source objekt
//string destinationPropertyName = typeMap.GetPropertyMaps() //GetCustomPropertyMaps()
// .Where(propertyMap => propertyMap.SourceMember.Name == node.Member.Name)
// .Select(propertyMap => propertyMap.DestinationProperty.Name).Single();
var newMember = _entityParameter.Type.GetMember(destinationPropertyName).First();
return Expression.MakeMemberAccess(reducedExpression, newMember);
}
//Recurse down to see if we can simplify...
var expression = Visit(node.Expression);
//If we've ended up with a constant, and it's a property or a field,
//we can simplify ourselves to a constant
var constantExpression = expression as ConstantExpression;
if (constantExpression != null)
{
object container = constantExpression.Value;
object value = null;
var memberAsFieldInfo = node.Member as FieldInfo;
var memberAsPropertyInfo = node.Member as PropertyInfo;
if (memberAsFieldInfo != null)
{
value = memberAsFieldInfo.GetValue(container);
}
if (memberAsPropertyInfo != null)
{
value = memberAsPropertyInfo.GetValue(container, null);
}
if (value != null)
{
return Expression.Constant(value);
}
}
return base.VisitMember(node);
}
catch (System.Exception exc)
{
var ex = exc.Message;
throw;
}
}
//change type from dto to entity --> otherwise the generated expression tree would throw an exception, because of missmatching types(Dto can't be used in Entity expression).
protected override Expression VisitParameter(ParameterExpression node)
{
return node.Type == _dtoParameter.Type ? _entityParameter : node;
}
}
It was working great but I faced an issue when I had property of the same type inside my DTO:
public class InventoryApplicationDto
{
public int Id { get; set; }
public string Name{ get; set; }
public InventoryApplicationDto ParentApplication { get; set; }
}
First of all I had to change:
string destinationPropertyName = typeMap.GetPropertyMaps()
.Where(propertyMap => propertyMap.SourceMember.Name == node.Member.Name)
.Select(propertyMap => propertyMap.DestinationProperty.Name).Single();
To:
string destinationPropertyName = typeMap.GetPropertyMaps()
.Where(propertyMap => propertyMap.SourceMember.Name == node.Member.Name)
.Select(propertyMap => propertyMap.DestinationProperty.Name).FirstOrDefault();
My problem is that I am getting error:
System.ArgumentException: Property 'Int32 ID' is not defined for type 'InventoryApplicationDto'
on line:
return Expression.MakeMemberAccess(reducedExpression, newMember);
Is MakeMemberAccess method case sensitive or there is another issue?
Aucun commentaire:
Enregistrer un commentaire