1

I've recently changed how i get users to enter dates into my website. it used to be a text box and they type it in but after receiving feedback it seems people would prefer to have 3 drop downs as DD MM YYYY. I've added this into my website using some code i found on SO.

To implement it I had to create a class to get around invalid data validation, my class looks like this

public class DateSelector : ICustomMappings {
    public DateSelector() : this(System.DateTime.MinValue) { }
    public DateSelector(DateTime date) {
        Year = date.Year;
        Month = date.Month;
        Day = date.Day;
    }

    [Required]
    public int Year { get; set; }

    [Required, Range(1, 12)]
    public int Month { get; set; }

    [Required, Range(1, 31)]
    public int Day { get; set; }

    public DateTime? DateTime {
        get {
            DateTime date;
            if (!System.DateTime.TryParseExact(string.Format("{0}/{1}/{2}", Year, Month, Day), "yyyy/M/d", CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
                return null;
            else
                return date;
        }
    }

    public void CreateMappings(IConfiguration configuration) {
        configuration.CreateMap<DateTime, DateSelector>()
            .ForMember(dest=>dest.DateTime,opt=>opt.Ignore())
            .ForMember(dest => dest.Day, opt => opt.MapFrom(src => src.Day))
            .ForMember(dest => dest.Month, opt => opt.MapFrom(src => src.Month))
            .ForMember(dest => dest.Year, opt => opt.MapFrom(src => src.Year));
    }
}

Automapper worked great when it was a text box but now ive split it into dropdowns i get the following error.

The binary operator NotEqual is not defined for the types 'System.DateTime' and 'System.Object'.

I think I'm getting it because its trying to map DateTime to my class, how do i get around this?

EDIT: Here is my controller which calls a method to get data from my database and then uses the extension method .Project()

public ActionResult EditYoungPerson(int youngPersonId) {

    YoungPerson.EditYoungPersonViewModel editYoungPersonViewModel = new YoungPerson.EditYoungPersonViewModel();

    editYoungPersonViewModel.YoungPerson = Context.GetYoungPersonDetailsForYoungPersonId(youngPersonId).Project().To<YoungPerson._YoungPersonViewModel>().Single();

    return View(editYoungPersonViewModel);
}

and here is the stack trace

[InvalidOperationException: The binary operator NotEqual is not defined for the types 'System.DateTime' and 'System.Object'.]
System.Linq.Expressions.Expression.GetEqualityComparisonOperator(ExpressionType binaryType, String opName, Expression left, Expression right, Boolean liftToNull) +4026223
System.Linq.Expressions.Expression.NotEqual(Expression left, Expression right) +73
AutoMapper.QueryableExtensions.Extensions.BindMappedTypeExpression(IMappingEngine mappingEngine, PropertyMap propertyMap, ExpressionResolutionResult result, MemberInfo destinationMember, IDictionary`2 typePairCount) +268
AutoMapper.QueryableExtensions.Extensions.CreateMemberBindings(IMappingEngine mappingEngine, TypePair typePair, TypeMap typeMap, Expression instanceParameter, IDictionary`2 typePairCount) +1477
AutoMapper.QueryableExtensions.Extensions.CreateMapExpression(IMappingEngine mappingEngine, TypePair typePair, Expression instanceParameter, IDictionary`2 typePairCount) +363
AutoMapper.QueryableExtensions.Extensions.CreateMapExpression(IMappingEngine mappingEngine, TypePair typePair, IDictionary`2 typePairCount) +119
AutoMapper.QueryableExtensions.<>c__DisplayClass1`2.<CreateMapExpression>b__0(TypePair tp) +119
System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) +85
AutoMapper.Internal.ConcurrentDictionaryImpl`2.GetOrAdd(TKey key, Func`2 valueFactory) +67
AutoMapper.QueryableExtensions.Extensions.CreateMapExpression(IMappingEngine mappingEngine) +322
AutoMapper.QueryableExtensions.ProjectionExpression`1.To() +111
Portal.Controllers.YoungPersonController.EditYoungPerson(Int32 youngPersonId) in c:\tfs\Portal\Dev\Portal.UI\Controllers\YoungPersonController.cs:278
lambda_method(Closure , ControllerBase , Object[] ) +161
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +14
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +208
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +27
System.Web.Mvc.Async.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41() +28
System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +10
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +57
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +48
System.Web.Mvc.Async.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33() +57
System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +223
System.Web.Mvc.Async.<>c__DisplayClass37.<BeginInvokeActionMethodWithFilters>b__36(IAsyncResult asyncResult) +10
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +57
  System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +48
System.Web.Mvc.Async.<>c__DisplayClass2a.<BeginInvokeAction>b__20() +24
System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__22(IAsyncResult asyncResult) +102
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +57
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +43
System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__18(IAsyncResult asyncResult) +14
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +57
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +47
        System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10
System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__3(IAsyncResult asyncResult) +25
System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +23
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +47
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
    System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9651116
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

EDIT: I've missed the ViewModel out which uses the DataSelector class.

        public class _YoungPersonViewModel ICustomMappings {

        public int YoungPersonId { get; set; }
        public string FirstName { get; set; }
        public string Surname { get; set; }
        public string FullName { get { return FirstName + " " + Surname; } }
        public DateSelector DateOfBirth { get; set; }
        public IEnumerable<SelectListItem> GenderTypeList { get; set; }

        public void CreateMappings(IConfiguration configuration) {
            configuration.CreateMap<Entities.Models.YoungPerson, _YoungPersonViewModel>()

                .ForMember(dest => dest.DateOfBirth, opt=>opt.MapFrom(src=>src.DateOfBirth));
        }
    }
Stephen E.
  • 252
  • 2
  • 17

1 Answers1

1

Try using ProjectUsing:

configuration.CreateMap<DateTime, DateSelector>()
    . ProjectUsing(src => new DateSelector(src));

?

Jimmy Bogard
  • 26,045
  • 5
  • 74
  • 69
  • Did you mean .convertUsing? as that seems to make it render, but its not passing the data through. Ive actually missed another ViewModel which is been used so ive edited my question to include it – Stephen E. Jan 06 '15 at 21:09
  • After more investigation I've found that it is to do with the mappings within my _YoungPersonViewModel not in the DateSelector class, do you have any idea how i need to map? .dest.DateOfBirth is DateSelector and src.DateOfBirth is DateTime – Stephen E. Jan 07 '15 at 09:10
  • No, ConvertProjectionUsing is for LINQ. ConvertUsing can't be used in LINQ. – Jimmy Bogard Jan 08 '15 at 21:58
  • I dont seem to have ConvertProjectionUsing, is it an extension to AutoMapper? – Stephen E. Jan 09 '15 at 20:00
  • ah, I was using an old version of AutoMapper. in my _YoungPersonViewModel When its mapping I am getting the following error now. Only parameterless constructors and initializers are supported in LINQ to Entities – Stephen E. Jan 14 '15 at 22:50