Randy Randy - 3 months ago 22
C# Question

Why does AutoMapper not map my child object?

I have two entities(tables) Person and Address. Address is a child entity of Person.

public class Person
{
public Person()
{
Addresses = new ObservableCollection<Address>();
}

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[DisplayName("Primary Key")]
[ScaffoldColumn(false)]
public int Id { get; set; }

[Required]
[DisplayName("First Name")]
[StringLength(25, MinimumLength = 3)]
public string FirstName { get; set; }

[DisplayName("Middle Name")]
[MaxLength(25)]
public string MiddleName { get; set; }

[Required]
[DisplayName("Last Name")]
[StringLength(25, MinimumLength = 3)]
public string LastName { get; set; }

public string FullName => $"{FirstName} {LastName}";

[Required]
[DisplayName("Date of Birth")]
[DataType(DataType.Date)]
public DateTime BirthDate { get; set; }

public ObservableCollection<Address> Addresses { get; set; }
}


public class Address
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[DisplayName("Primary Key")]
[ScaffoldColumn(false)]
public int Id { get; set; }
public int OwnerId { get; set; }
public Person Owner { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
}


Both tables have a (almost) mirror image archive table named PersonArchive and AddressArchive respectively.

public class PersonArchive
{
public PersonArchive()
{
Addresses = new ObservableCollection<AddressArchive>();
}

[Key]
[DisplayName("Primary Key")]
[ScaffoldColumn(false)]
public int Id { get; set; }

[Required]
[DisplayName("First Name")]
[StringLength(25, MinimumLength = 3)]
public string FirstName { get; set; }

[DisplayName("Middle Name")]
[MaxLength(25)]
public string MiddleName { get; set; }

[Required]
[DisplayName("Last Name")]
[StringLength(25, MinimumLength = 3)]
public string LastName { get; set; }

public string FullName => $"{FirstName} {LastName}";

[Required]
[DisplayName("Date of Birth")]
[DataType(DataType.Date)]
public DateTime BirthDate { get; set; }

public ObservableCollection<AddressArchive> Addresses { get; set; }
}

public class AddressArchive
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[DisplayName("Primary Key")]
[ScaffoldColumn(false)]
public int Id { get; set; }
public int OwnerId { get; set; }
public PersonArchive Owner { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
}


In the Person table each field matches the type, except one, the Addresses field is of a collection of Address and the corresponding field in PeopleArchive is of type AddressArchive. Same for Address's field Owner.

using (ArchiveDemoContext context = new ArchiveDemoContext())
{

//Person p = context.People.Include("Addresses").FirstOrDefault();
Person p = context.People.FirstOrDefault();

MapperConfiguration config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Person, PersonArchive>()
.ForMember(dest => dest.Addresses, opt => opt.MapFrom(src => src.Addresses));
cfg.CreateMap<Address, AddressArchive>()
.ForMember(dest => dest.Owner, opt => opt.MapFrom(src => src.Owner));
});

config.AssertConfigurationIsValid();

IMapper mapper = config.CreateMapper();

PersonArchive person = mapper.Map<Person, PersonArchive>(p);
//context.People.Remove(p);

context.PeopleArchive.Add(person);

context.SaveChanges();
}


Debugging the code does not give me any Exceptions, however, only the Person is archived and not the Address.

Thanks in Advance,

Answer

You don't need to map your Address back to the owner as long as you are setting it's owner Id. Change your mapping:

cfg.CreateMap<Address, AddressArchive>()
      .ForMember(dest => dest.Owner, opt => opt.Ignore());
Comments