J'ai un PersonDTO de classe avec la propriété Nullable DateTime:Comment remplacer le type de propriété et sa valeur dans les arbres d'expression
public class PersonDTO
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
// YYYYMMDD format
public virtual Nullable<int> Birthday { get; set; }
}
Et une classe dans la couche de présentation:
public class PersonViewModel
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual Nullable<DateTime> Birthday { get; set; }
}
Sur mon formulaire je deux méthodes qui sont responsables de la création objet Expression<Func<PersonViewModel, bool>>
:
private Expression<Func<PersonViewModel, bool>> GetFilterExpression()
{
Expression condition = null;
ParameterExpression pePerson = Expression.Parameter(typeof(PersonViewModel), "person");
//...
if (dtpBirth.Format != DateTimePickerFormat.Custom)
{
Expression target = Expression.Property(pePerson, pePerson.Type.GetProperty("Birthday", typeof(DateTime?)));
UnaryExpression date = Expression.Convert(Expression.Constant(dtpBirth.Value.Date), typeof (DateTime?));
condition = (condition == null)
? Expression.GreaterThan(target, date)
: Expression.And(condition, Expression.GreaterThan(target, date));
}
// Формируем лямбду с условием и возвращаем результат сформированного фильтра
return condition != null ? Expression.Lambda<Func<PersonViewModel, bool>>(condition, pePerson) : null;
}
aussi je suis usin g AutoMapper? qui convertit un Expression<Func<PersonViewModel, bool>>
en Expression<Func<PersonDTO, bool>>
. Le code pour la conversion ressemble:
// ...
Mapper.CreateMap<PersonViewModel, PersonDTO>()
.ForMember(dto => dto.Birthday, opt => opt.MapFrom(model => model.BirthdaySingle.NullDateTimeToNullInt("yyyyMMdd")));
// ...
public static class DataTypesExtensions
{
public static DateTime? NullIntToNullDateTime(this int? input, string format)
{
if (input.HasValue)
{
DateTime result;
if (DateTime.TryParseExact(input.Value.ToString(), format, CultureInfo.InvariantCulture, DateTimeStyles.None, out result))
{
return result;
}
}
return null;
}
//...
}
Mon convertisseur d'expression ressemble à:
public static Expression<Func<TDestination, TResult>> RemapForType<TSource, TDestination, TResult>(
this Expression<Func<TSource, TResult>> expression)
{
var newParameter = Expression.Parameter(typeof(TDestination));
var visitor = new AutoMapVisitor<TSource, TDestination>(newParameter);
var remappedBody = visitor.Visit(expression.Body);
if (remappedBody == null)
{
throw new InvalidOperationException("Unable to remap expression");
}
return Expression.Lambda<Func<TDestination, TResult>>(remappedBody, newParameter);
}
public class AutoMapVisitor<TSource, TDestination> : ExpressionVisitor
{
private readonly ParameterExpression _newParameter;
private readonly TypeMap _typeMap = Mapper.FindTypeMapFor<TSource, TDestination>();
public AutoMapVisitor(ParameterExpression newParameter)
{
_newParameter = newParameter;
}
protected override Expression VisitMember(MemberExpression node)
{
var propertyMaps = _typeMap.GetPropertyMaps();
// Find any mapping for this member
// Here I think is a problem, because if it comes (person.Birthday => Convert(16.11.2016 00:00:00)) it can't find it.
var propertyMap = propertyMaps.SingleOrDefault(map => map.SourceMember == node.Member);
if (propertyMap == null)
{
return base.VisitMember(node);
}
var destinationProperty = propertyMap.DestinationProperty;
var destinationMember = destinationProperty.MemberInfo;
// Check the new member is a property too
var property = destinationMember as PropertyInfo;
if (property == null)
{
return base.VisitMember(node);
}
// Access the new property
var newPropertyAccess = Expression.Property(_newParameter, property);
return base.VisitMember(newPropertyAccess);
}
}
je dois en quelque sorte de convertir une partie d'une expression lambda: person => person.Birthday > Convert(15.11.2016 00:00)
(dans cette personne de cas est PersonViewModel et anniversaire de type DateTime?) À quelque chose qui ressemble à: person => person.Birthday > 20161115
(dans ce cas personne est PersonDTO et Birthday de type int?). Sans ce problème, tout est mappé et fonctionne correctement. Je comprends que j'ai besoin d'aller plus loin dans l'arbre et de faire quelques manipulations, mais je ne peux pas comprendre comment et où devrais-je faire cela.
Wow. Pouvez-vous réduire le code, mais cela reproduit toujours le problème? –
@Thomas Oui, je n'ai pas encore trouvé de réponse. Dans la méthode de la méthode Visitor SingleOrDefault ne trouve rien, donc la conversion n'agit pas comme prévu. – Dmitry
@ThomasWeller J'ai édité ma question – Dmitry