سؤال

I am getting the following exception when I try to call Mapper.Map in my application:

AutoMapper.AutoMapperMappingException. 

Mapping types:
Double -> Double
System.Double -> System.Double

Destination path:
Address.Latitude

Source value:
42.250287

   System.InvalidCastException. Unable to cast object of type 'Acme.Order' to type 'Acme.Address'.

Aside from the obvious frustration with an error indicating that it can't map objects of the same type (and primitive types at that), the fact is that I NEVER map from type "Acme.Order" to type "Acme.Address"!

Here is the actual call being used:

var order = Mapper.Map<IDataRecord, Order>(theDataReader);

My object model looks like this:

public class Order
{
    public Address Address { get; set; }
    public Int32 Number { get; set; }
    public PhoneNumber PhoneNumber { get; set; }
}

public class Address
{
    public String City { get; set; }
    public Double Latitude { get; set; }
    public Double Longitude { get; set; }
    public Int32 Number { get; set; }
    public String PostalCode { get; set; }
    public String State { get; set; }
    public String Street { get; set; }
}

public class PhoneNumber
{
    public String Extension { get; set; }
    public String Number { get; set; }
}

And I have the following configuration defined in my application:

CreateMap<IDataRecord, Address>()
.ForMember(target => target.Latitude, opt => opt.MapFrom(record => GetDoubleFrom(record, "Latitude", 0)))
.ForMember(target => target.Longitude, opt => opt.MapFrom(record => GetDoubleFrom(record, "Longitude", 0)))
;
CreateMap<IDataRecord, PhoneNumber>()
.ForMember(target => target.Extension, opt => opt.MapFrom(record => GetStringFrom(record, "Extension", String.Empty)))
.ForMember(target => target.Number, opt => opt.MapFrom(record => GetStringFrom(record, "PhoneNumber", String.Empty)))
;
CreateMap<IDataRecord, Order>()
.ForMember(target => target.Address, opt => opt.ResolveUsing(record => Mapper.Map<IDataRecord, Address>(record)))
.ForMember(target => target.PhoneNumber, opt => opt.ResolveUsing(record => Mapper.Map<IDataRecord, PhoneNumber>(record)))
;

With these helper methods:

private Double GetDoubleFrom(IDataRecord record, String name, Double defaultValue)
{
    return (record.Contains(name) && !record.IsDbNull(name)) ? record.GetDouble(name) : defaultValue;
}

private String GetStringFrom(IDataRecord record, String name, String defaultValue)
{
    return (record.Contains(name) && !record.IsDbNull(name)) ? record.GetString(name) : defaultValue;
}

(I have extension methods on IDataRecord that take the field name, get the ordinal and return the value using the standard methods but won't show them for brevity.)

Does any of this shed any light on what is causing the failure?

(Btw, I am using AutoMapper v2.1.267)

هل كانت مفيدة؟

المحلول

I can't recreate this directly as it is missing some information (such as the concrete class for the IDataRecord interface, the content of theDataReader, etc). However the first check would be to ensure your mapping is correct. Do you test it with AssertConfigurationIsValid?

For example, if you have the following AutoMapper profile:

public class MyProfile : Profile
{
    public override string ProfileName
    {
        get
        {
            return "MyProfile";
        }
    }

    protected override void Configure()
    {
        CreateMap<IDataRecord, Address>()
            .ForMember(
                target => target.Latitude,
                opt => opt.MapFrom(
                    record => GetDoubleFrom(record, "Latitude", 0)))
            .ForMember(
                target => target.Longitude,
                opt => opt.MapFrom(
                    record => GetDoubleFrom(record, "Longitude", 0)));
        CreateMap<IDataRecord, PhoneNumber>()
            .ForMember(
                target => target.Extension,
                opt => opt.MapFrom(
                    record => GetStringFrom(record, "Extension", string.Empty)))
            .ForMember(
                target => target.Number,
                opt => opt.MapFrom(
                    record => GetStringFrom(record, "PhoneNumber", string.Empty)));
        CreateMap<IDataRecord, Order>()
            .ForMember(
                target => target.Address,
                opt => opt.ResolveUsing(
                    record => Mapper.Map<IDataRecord, Address>(record)))
            .ForMember(
                target => target.PhoneNumber,
                opt => opt.ResolveUsing(
                    record => Mapper.Map<IDataRecord, PhoneNumber>(record)));
    }
}

Will this Unit Test pass?

[Test]
public void AutoMapper_Configuration_IsValid()
{
    Mapper.Initialize(m => m.AddProfile<MyProfile>());
    Mapper.AssertConfigurationIsValid();
}

UPDATE

Can you try

CreateMap<IDataRecord, Order>()
    .ForMember(
        target => target.Address,
        opt => opt.MapFrom(record => Mapper.Map<IDataRecord, Address>(record)))
    .ForMember(
        target => target.PhoneNumber,
        opt => opt.MapFrom(record => Mapper.Map<IDataRecord, PhoneNumber>(record)));
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top