我有一個類PersonDTO可空的DateTime屬性值:如何更換物業類型及其在表達式樹
public class PersonDTO
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
// YYYYMMDD format
public virtual Nullable<int> Birthday { get; set; }
}
而在表示層的類:
public class PersonViewModel
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual Nullable<DateTime> Birthday { get; set; }
}
在我的表我有兩種方法負責創建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;
}
另外我是usin g AutoMapper?其將一個Expression<Func<PersonViewModel, bool>>
轉換成Expression<Func<PersonDTO, bool>>
。轉換的代碼如下所示:
// ...
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;
}
//...
}
我的表情轉換器看起來像:
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);
}
}
我需要以某種方式部分轉換lambda表達式:person => person.Birthday > Convert(15.11.2016 00:00)
(在這種情況下,人的類型爲PersonViewModel和生日DateTime?)看起來像這樣:person => person.Birthday > 20161115
(在這種情況下,personDTO和生日類型int?)。沒有這個問題,所有的東西都能正確地映射和工作我知道我需要深入樹並做一些操作,但我無法理解如何以及在哪裏應該這樣做。
哇。你能否讓這個代碼更小,但它仍然會重現這個問題? –
@Thomas是的,我還沒有找到答案。在Visitor方法中SingleOrDefault找不到任何內容,因此轉換不會按預期方式進行。 – Dmitry
@ThomasWeller我編輯了我的問題 – Dmitry