David Molnar
David Molnar

Reputation: 479

inherited class AutoMapper.AutoMapperMappingException

I am new at automapper and it is a very good stuff easy to use, but now I have a problem with it. Trying to convert my derived class to base and it gives me

AutoMapper.AutoMapperMappingException

Missing type map configuration or unsupported mapping.

Mapping types: ClientEventDb -> EventId
Database.ClientEventDb -> EventId

Destination path: ClientEvent

Source value:

Event:Login

Automapper wants to convert ClientEventDb to EventId? I don't understand why. EventId is an enum...

Please help me I have run out of ideas.

Here is the code which I run:

ClientEventDb[] edbl;
using (var context = new DbEntities())
{
    edbl=context.Events.Take(1000).ToArray();
}
Mapper.CreateMap<ClientEventDb, ClientEvent>();
Console.WriteLine("hello");
return edbl.Select(edb => Mapper.Map<ClientEvent>(edb)).ToArray();

Here are my classes

   [Table("events", Schema = "public")]
    public class ClientEventDb : ClientEvent
    {
        public ClientEventDb(string userName, EventId happening, object userObject = null)
            : base(userName, happening, userObject)
        {

        }
        public ClientEventDb()
        {

        }
    }

[ProtoContract]
[Table("events", Schema = "public")]
public class ClientEvent : ClientEventBase
{
    [ProtoMember(1)]
    [Column("username")]
    public string UserName { get; private set; }

    [ProtoMember(2)]
    [Column("time")]
    public DateTime DateTime { get; private set; }

    [ProtoMember(3)]
    [Key]
    [Column("id")]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public string Id { get; private set; }

    [ProtoMember(4)]
    [Column("data")]
    public byte[] UserObject { get; set; }

    public ClientEvent(string userName,EventId happening, object userObject=null) : base(happening)
    {
        UserName = userName;
        DateTime = DateTime.Now;
        //UserObject = null;
        if (userObject!=null) throw new NotImplementedException();
    }
    public ClientEvent()
    {

    }
    protected ClientEvent Clone()
    {
        return (ClientEvent)MemberwiseClone();
    }
}

[ProtoContract]
[ProtoInclude(10, typeof(ClientEvent))]
public class ClientEventBase
{

    [Column("eventid")]
    [ProtoMember(1)]
    public int EventIdValue { get; set; } //must be public because of entity framework

    [NotMapped]
    public EventId EventId
    {
        get { return (EventId) EventIdValue; }
        set { EventIdValue = (int) value; }
    }

    public ClientEventBase(EventId eventId)
    {
        EventId = eventId;
    }
    public ClientEventBase()
    {

    }
    public override string ToString()
    {
        return String.Format("Event:{0}",EventId);
    }
}

public enum EventId
{
    Login = 1,
    Logout,
    ExitApplication,
}

UPDATE

bugfix: ClientEvent [Key] attribute moved to id property

Solution was this (thx to stuartd):

ClientEventDb[] edbl;
using (var context = new DbEntities())
{
    edbl=context.Events.ToArray();
}
Mapper.CreateMap<ClientEventDb, ClientEvent>().ConstructUsing((ClientEventDb src) => new ClientEvent());
return edbl.Select(Mapper.Map<ClientEvent>).ToArray();

Upvotes: 1

Views: 260

Answers (2)

ajg
ajg

Reputation: 1753

AutoMapper is confused as its made to map between similar properties in different classes, you are using it incorrectly - you just need to go from the derived class to the base which does not require AutoMapper. You could use this to do what you need....

ClientEventDb[] edbl;
using (var context = new DbEntities())
{
    edbl=context.Events.Take(1000).ToArray();
}

return edbl.Cast<ClientEvent>().ToList();

I'd be looking at why you even feel you need a derived ClientEventDb though - understand we dont have the whole picture here but it seems to do nothing in addition to what the base class already does.

Upvotes: 4

stuartd
stuartd

Reputation: 73243

The issue is that ClientEvent has two constructors but you have not told AutoMapper which to use.

If you want it to use your constructor with parameters, change your mapping code to this and it will work:

Mapper.CreateMap<ClientEventDb, ClientEvent>()
      .ConstructUsing(src => new ClientEvent(src.UserName, src.EventId));

Or to make AutoMapper use the default constructor:

Mapper.CreateMap<ClientEventDb, ClientEvent>()
      .ConstructUsing((ClientEventDb src) => new ClientEvent());

Upvotes: 2

Related Questions