0
 public class CreateOrEditOwnerDetailInput : IInputDto
    {
        [Required]
        public OwnerDetailEditDto OwnerDetail { get; set; }
    }

    [AutoMap(typeof(OwnerDetail))]
    public class OwnerDetailEditDto
    {
        public const int MaxLength = 50;
        public const int NotesMaxLength = 300;

        public int? Id { get; set; }

        [Required]
        [MaxLength(MaxLength)]
        public string LastName { get; set; }


        [Required]
        [MaxLength(MaxLength)]
        public string CompanyName { get; set; }

        [Required]
        public OwnerContactDetailDto ContactDetail { get; set; }

        [Required]
        public AdditionalAddressDto AdditionalAddress { get; set; }

    }



 [Table("IpOwnerDetails")]
    public class OwnerDetail : FullAuditedEntity
    {
        public const int MaxLength = 50;
        public const int NotesMaxLength = 300;

        [Required]
        [MaxLength(MaxLength)]
        public virtual string LastName { get; set; }

        [Required]
        [MaxLength(MaxLength)]
        public virtual string CompanyName { get; set; }


        [ForeignKey("AdditionalAddressId")]
        public virtual AdditionalAddress AdditionalAddress { get; set; }
        public virtual int AdditionalAddressId { get; set; }

        [ForeignKey("ContactDetailId")]
        public virtual ContactDetail ContactDetail { get; set; }
        public virtual int ContactDetailId { get; set; }


    }

public class OwnerContactDetailDto : FullAuditedEntityDto
    {
        public const int NumberMaxLength = 20;

        [Required]
        [MaxLength(NumberMaxLength)]
        public string MainPhoneNumber { get; set; }

        [MaxLength(NumberMaxLength)]
        public string HomePhoneNumber { get; set; }

        [Required]
        public ContactDetailType Type { get; set; }
    }

  public class AdditionalAddressDto : FullAuditedEntityDto, IOutputDto
    {
        public const int MaxLength = 50;

        [Required]
        [MaxLength(MaxLength)]
        public string StreetNumber { get; set; }

        [Required]
        public AddressType Type { get; set; }

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

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


    }

Mapper.CreateMap<AdditionalAddress, AdditionalAddressDto>()
              .ReverseMap()
              .ForMember(additionalAddress => additionalAddress.Id, options => options.Ignore());

            Mapper.CreateMap<ContactDetail, OwnerContactDetailDto>()
              .ReverseMap()
              .ForMember(contactDetail => contactDetail.Id, options => options.Ignore());


 public async Task<int?> EditOwnerDetailAsync(CreateOrEditOwnerDetailInput input)
        {
            var ownerDetail = await _ownerDetailRepository.FirstOrDefaultAsync(p => p.Id == input.OwnerDetail.Id);
            input.OwnerDetail.MapTo(ownerDetail);//after this it goes null
            await _ownerDetailRepository.UpdateAsync(ownerDetail);
            return input.OwnerDetail.Id;

        }

Image url : https://i.stack.imgur.com/6DMsK.jpg

Q : After the mapping inside the EditOwnerDetailAsync method where both AdditionalAddress and ContactDetail goes to null.Could you tell me why ? Please see the image for more info.

Exception :

    ERROR 2015-11-20 17:56:18,666 [26   ] lers.Filters.AbpExceptionFilterAttribute - System.Data.Entity.Infrastructure.DbUpdateException: An error occurred while 
updating the entries. See the inner exception for details. ---> 
System.Data.Entity.Core.UpdateException: An error occurred while updating the 
entries. See the inner exception for details. ---> 
System.Data.SqlClient.SqlException: The UPDATE statement conflicted with the 
FOREIGN KEY constraint 
"FK_dbo.IpOwnerDetails_dbo.IpAdditionalAddresses_AdditionalAddressId". The 
conflict occurred in database "IP", table "dbo.IpAdditionalAddresses", column 'Id'.
    The statement has been terminated.

NOTE : The strange thing here is when I bring the debug pointer back to the input.OwnerDetail.MapTo(ownerDetail); line (2nd time) then it fills data for the AdditionalAddress and ContactDetail objects.How can It be happened ?

Sampath
  • 63,341
  • 64
  • 307
  • 441
  • Is `MapTo` an extension method? Can you show the code in it? – stuartd Nov 20 '15 at 10:53
  • @stuartd Yes,Please see this doc..http://www.aspnetboilerplate.com/Pages/Documents/Data-Transfer-Objects – Sampath Nov 20 '15 at 11:36
  • The extension method [appears to be using the correct overload of Map (the one that does not overwrite the existing object)](https://github.com/aspnetboilerplate/aspnetboilerplate/blob/master/src/Abp.AutoMapper/AutoMapper/AutoMapExtensions.cs), so it isn't that. – stuartd Nov 20 '15 at 12:09
  • @stuartd Sorry I couldn't get that ? – Sampath Nov 20 '15 at 12:17
  • Well, a common cause of this problem is calling `existingObject = Mapper.Map(source)` - which creates a new object, overwriting the existing one. However `MapTo` seems to call `Mapper.Map(source, existingObject )` which preserves the existing values. Are you using the most recent version of Abp.AutoMapper? – stuartd Nov 20 '15 at 12:19
  • @stuartd Ver : 4.0.4.0 – Sampath Nov 20 '15 at 12:21
  • @stuartd Could you tell me why this is happening? Did you see the above image ? – Sampath Nov 20 '15 at 12:24
  • @stuartd I have updated the exception which it gives due to `null` objects.Please see that too... – Sampath Nov 20 '15 at 12:32

1 Answers1

-1

The mappings with AutoMapper are done either by convention or by configuration. For nested properties, suppose you have two have nested properties as source of your map like

public class OuterSrc{
   public string Name {get;set;}
   public InnerSrc Source{get; set;} 
}
public class InnerSrc{
   public string Title{get; set;}
}

and for destination you have a single class like

public class Destination
{
    public string Name{get; set;}
    public string Title{get;set;}
}

If you define a default mapping from OuterSrc to Destination would Title form InnerSrc map to Title property of Destination. The plain answer is no because, the properties are not named according to AutoMapper conventions.
So in this case, I have couple of options. Firstly, I can change the property name to match conventions like

public class Destination{
   public string Name{get;set;} // as earlier
   public string SourceTitle{get;set;} // see the change here. Source is //property in `OuterSrc` and `Title` is property in `InnerSrc`. I just merged //them
}

If you think, this solution is not viable, you can define such mappings in configurations like

AutoMapper.Mapper.CreateMap<OuterSrc, Destination>()
    .ForMember(dest => dest.Title,
               opts => opts.MapFrom(src => src.Source.Title));

By doing this, your mapper will know how to map your inner properties.

Muhammad Adeel Zahid
  • 17,474
  • 14
  • 90
  • 155