1

I have an entity that looks like this:

public class Author : BaseEntity
{
    public virtual string Name { get; private set; }
    public virtual Address PhysicalAddress { get; private set; }

    [JsonIgnore]
    [IgnoreDataMember]
    [ForeignKey("Recipe")]
    public virtual Guid RecipeId { get; private set; }
    public virtual Recipe Recipe { get; private set; }


    public static Author Create(AuthorForCreationDto authorForCreationDto)
    {
        new AuthorForCreationDtoValidator().ValidateAndThrow(authorForCreationDto);
        var config = new TypeAdapterConfig();
        config.Apply(new AuthorProfile());
        var mapper = new MapsterMapper.Mapper(config);
        var newAuthor = mapper.Map<Author>(authorForCreationDto);
        
        newAuthor.QueueDomainEvent(new AuthorCreated(){ Author = newAuthor });
        
        return newAuthor;
    }

    public void Update(AuthorForUpdateDto authorForUpdateDto)
    {
        new AuthorForUpdateDtoValidator().ValidateAndThrow(authorForUpdateDto);
        var config = new TypeAdapterConfig();
        config.Apply(new AuthorProfile());
        var mapper = new MapsterMapper.Mapper(config);
        mapper.Map(authorForUpdateDto, this);
        
        QueueDomainEvent(new AuthorUpdated(){ Id = Id });
    }
    
    protected Author() { } // For EF + Mocking
}

The problem is, if When I set up my mapper (below) and try to create an Author, I can't because I don't have a default constructor

public class AuthorProfile : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        config.NewConfig<string, PostalCode>()
            .MapWith(src => new PostalCode(src));
        config.NewConfig<PostalCode, string>()
            .MapWith(src => src.Value);
        config.NewConfig<Address, AddressDto>()
            .TwoWays();
        config.NewConfig<AddressForCreationDto, Address>()
            .MapWith(src => new Address(src.Line1, src.Line2, src.City, src.State, src.PostalCode, src.Country))
            .TwoWays();
        config.NewConfig<AddressForUpdateDto, Address>()
            .MapWith(src => new Address(src.Line1, src.Line2, src.City, src.State, src.PostalCode, src.Country))
            .TwoWays();
        
        config.NewConfig<Author, AuthorDto>()
            .TwoWays();
        config.NewConfig<AuthorForCreationDto, Author>()
            .TwoWays();
        config.NewConfig<Author, AuthorForUpdateDto>()
            .TwoWays();
    }
}

Error:

  ----> System.InvalidOperationException : No default constructor for type 'Author', please use 'ConstructUsing' or 'MapWith'

But then, when I try and use 'ConstructUsing' or 'MapWith'

config.NewConfig<AuthorForCreationDto, Author>()
    .ConstructUsing(x => Author.Create(x));

I get an error, presumably because it is recursively trying to use a mapping inside the creation factory and using the factory for the mapping.

Exit code is 134 (Output is too long. Showing the last 100 lines:

   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[[System.Int32, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()

On top of that, I don't even have a good option for something like the Update since the creation factory uses an Update dto and not a creation (though it could theoretically map one to the other?).


config.NewConfig<Author, AuthorForUpdateDto>()
    .ConstructUsing(x => Author.Create(x))

Has anyone ran into this before? Any thoughts on potential solutions, other than manually mapping in the factories and using the above for all other maps?

Paul DeVito
  • 1,542
  • 3
  • 15
  • 38

0 Answers0