I have the following Entity Framework Entities:
public class Region
{
public int RegionId { get; set; } // Primary Key
public string Name { get; set; }
public virtual ICollection<Country> Countries { get; set; } // Link Table
}
public class Country
{
public int CountryId { get; set; } // Primary Key
public string Name { get; set; }
public int RegionId { get; set; } // Foreign Key
}
I map these using AutoMapper to the following ViewModels:
public class RegionViewModel
{
public int RegionId { get; set; }
public string Name { get; set; }
public virtual ICollection<int> Countries { get; set; }
}
public class CountryViewModel
{
public int CountryId { get; set; }
public string Name { get; set; }
}
I want to translate my ViewModels to Entities using AutoMapper so I can save a new Region. This is my mapping code:
Mapper.CreateMap<RegionViewModel, Region>()
.ForMember(x => x.Countries, x => x.MapFrom(y => y.Countries.Select(z => new Country() { CountryId = z }).ToArray()));
This causes an exception when adding the region in the repository as it also tries to create a new instance of Country with a null Name. One solution is to change the Add
method in my repository to set the State of the country objects to Unchanged.
public async Task Add(Region region)
{
foreach (Country country in region.Countries)
{
this.Context.Entry(country).State = EntityState.Unchanged;
}
await base.Add(region);
}
The other alternative solution is to use more complicated translation logic which uses another repository to get the real country objects. This approach has slower performance because it has to make an extra call to the database but you also get a more complete Region object.
Mapper.CreateMap<RegionViewModel, Region>();
Mapper.CreateMap<int[], Country[]>().ConvertUsing(x => countryRepository.GetAll().Result.Where(y => x.Contains(y.CountryId)).ToArray());
I lean to the first one but what is the correct approach?
AutoMapper supports polymorphic arrays and collections, such that derived source/destination types are used if found.
AutoMapper in C# is a library used to map data from one object to another. It acts as a mapper between two objects and transforms one object type into another. It converts the input object of one type to the output object of another type until the latter type follows or maintains the conventions of AutoMapper.
Automapper is considerably faster when mapping a List<T> of objects on . NET Core (It's still slower on full . NET Framework).
The first method, together with the loop to set the states to UnChanged
, is definitely the best one. It is lightweight, because you don't needlessly fetch Country
s from the database. Instead, by the mapper part...
y.Countries.Select(z => new Country() { CountryId = z })
...you create stub entities, i.e. incomplete entities that serve as a placeholders for the real things. That's a commonly recommended approach to reduce network traffic.
Setting the states to UnChanged
is one of several ways to attach the stub Country
s to the context. You have to attach them before calling base.Add(region)
(which I assume adds the region to the Regions
of the context), because Add
marks all entities in an object graph off the added entity as new (Added
) when they're not yet attached to the context.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With