Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ExpressMapper / EntityFramework - No parameterless constructor defined for this object

Tags:

I am trying to use ExpressMapper to map data entities to models.

If I map entity to a model directly (both of them having same properties) then it is working fine.

But if I map linked entities to model then I am getting an error

There was an error: System.MissingMethodException: No parameterless constructor defined for this object.

Database structure:

enter image description here

ExpressMapper Registration:

Mapper.Register<DiscountDaysOfWeek, DiscountDaysOfWeekModel>()
      .Member(dest => dest.DiscountDayId, src => src.DiscountDayId)
      .Member(dest => dest.DiscountDaysOfWeekId, src => src.DiscountDaysOfWeekId)
      .Member(dest => dest.DiscountId, src => src.DiscountId)
      .Member(dest => dest.Discountday, src => src.DiscountDay.Day);

Invoked like this:

var disDays = discs.SelectMany(x => x.DiscountDaysOfWeeks)
                   .Map<IQueryable<DiscountDaysOfWeek>, IQueryable<DiscountDaysOfWeekModel>>();

Getting the error message at the invoke.

DiscountDaysOfWeekModel:

public class DiscountDaysOfWeekModel
{
    public int DiscountDaysOfWeekId { get; set; }
    public int DiscountId { get; set; }
    public int DiscountDayId { get; set; }
    public string Discountday { get; set; }
}

DiscountDayOfWeek (Generated by EF)

public partial class DiscountDaysOfWeek
{
    public int DiscountDaysOfWeekId { get; set; }
    public int DiscountId { get; set; }
    public int DiscountDayId { get; set; }

    public virtual DiscountDay DiscountDay { get; set; }
    public virtual Discount Discount { get; set; }
}

DiscountDay(Generated by EF):

public partial class DiscountDay
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public DiscountDay()
    {
        this.DiscountDaysOfWeeks = new HashSet<DiscountDaysOfWeek>();
    }

    public int DiscountDayId { get; set; }
    public string Day { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<DiscountDaysOfWeek> DiscountDaysOfWeeks { get; set; }
}

Sample working one: In the below working sample the model and entities are having same properties

Mapper.Register<DiscountPreventedPriceEnding, DiscountPreventedPriceEndingModel>();

var execPriceEndings = discs.SelectMany(x => x.DiscountPreventedPriceEndings)
                            .Map<IQueryable<DiscountPreventedPriceEnding>, IQueryable<DiscountPreventedPriceEndingModel>>();

Any help would be greatly appreciated.

like image 579
Rocky Avatar asked Jun 23 '16 15:06

Rocky


1 Answers

I appreciate this is an extremely old question, but given that I just spent 4 hours debugging a similar There was an error: System.MissingMethodException: No parameterless constructor defined for this object error on ExpressMapper, I thought I'd chime in with my findings.

So we had a situation similar to yours, in that we had domain models like so (all the following is simplified examples):

public class Owner 
{
    public int? ID { get; set; }
    public string Name { get; set; }
}

public class Animal
{
    public int? ID { get; set; }
    public string Name { get; set; }
    public int? OwnerID { get; set; }
    [ForeignKey("OwnerID")]
    public Owner Owner { get; set; }
}

With the following view model (i.e. what our APIs send out and receive):

public class AnimalViewModel
{
    public int? ID { get; set; }
    public string Name { get; set; }
    public string Owner { get; set; }
}

With mappings like so:

Mapper.Register<Animal, AnimalViewModel>();
Mapper.Register<AnimalViewModel, Animal>();

On mapping to or from the domain model and the view model we'd get the MissingMethodException, despite the fact that both the view model and the domain model had public, default constructors. The solution was to manually map the related entities in the domain model and exclude them from ExpressMapper's mappings like so:

Mapper.Register<Animal, AnimalViewModel>()
    .Ignore(a => a.Owner);
Mapper.Register<AnimalViewModel, Animal>()
    .Ignore(a => a.Owner);

From reading EntityMapper's source code, it seems the MissingMethodException is a total red herring which has nothing to do with the actual issue. The actual issue seems to be that it can't figure out how to convert one type to another. In our case -- where complex objects were mapped to/from primitives as above -- it was sufficient to exclude the related objects from the mapper and do it manually.

EDIT:

Upon further investigation, we traced the root problem in our case back to the fact that EF proxy creation creates generated types (e.g. 'MyModel_14289012') which don't match the types registered in the mapper. To prevent this, apply the following to your context:

Context.Configuration.LazyLoadingEnabled = false;
Context.Configuration.ProxyCreationEnabled = false;

and manually include any nested/related objects required in your model like so:

Context.Animals
    .Include(a => a.Owner);

This fetches the related entities, but as their actual type rather than the EF-generated type.

like image 112
Ben H Avatar answered Sep 28 '22 01:09

Ben H