I have the following two classes:
public class ADto
{
public int Id { get; set; }
public List<BDto>? BSet { get; set; }
}
public class A
{
public int Id { get; set; }
public virtual ICollection<B>? BSet { get; set; }
}
I use Automapper to convert the incoming ADto
to A
, then create A.
AutoMapper mapping profile:
CreateMap<A, ADto>();
CreateMap<B, BDto>();
Code:
public async Task<OperationResultDto> CreateAsync(A aDto, CancellationToken cancellationToken)
{
// Create & Map the record
A a = new();
mapper.Map(aDto, a);
// Create the object in database
await repository.CreateAsync(a, cancellationToken);
}
I get the following error:
SqlException: Cannot insert explicit value for identity column in table 'base_qamarks' when IDENTITY_INSERT is set to OFF.
Now I can solve this issue by doing the following in AutoMapper:
CreateMap<A, ADto>()
.ForMember(dest => dest.BSet, opt => opt.Ignore());
Then the manual assignment:
public async Task<OperationResultDto> CreateAsync(A aDto, CancellationToken cancellationToken)
{
// Create & Map the record
A a = new();
mapper.Map(aDto, a);
// Manually assign it
foreach (BDto bDto in A.BSet)
{
B? b = await bRepository.GetEntityAsync(bDto.Id, cancellationToken);
if (b != null)
{
a.BSet.Add(b);
}
}
// Create the object in database
await repository.CreateAsync(a, cancellationToken);
}
This works, but it is additional code and doesn't look good. How do I properly use AtuoMapper to map this?
I was able to resolve it... using a resolver:
public class AResolver : IValueResolver<ADto, A, ICollection<A>>
{
private readonly IARepository aRepository;
public CompanyRoleResolver(IARepository aRepository)
{
this.aRepository = aRepository;
}
public ICollection<A> Resolve(ADto source, A destination, ICollection<A> destMember, ResolutionContext context)
{
List<A> aSet = new();
if (source.ASet != null)
{
foreach(var aDto in source.aSet)
{
A? a = aRepository.GetEntityAsync(a?.Id ?? -1, CancellationToken.None).Result;
if (a != null)
{
aSet.Add(a);
}
}
}
return aSet;
}
}
Then in the mapping profile:
CreateMap<ADto, A>().ForMember(dest => dest.ASet, opt => opt?.MapFrom<AResolver>())
But you need to register the resolver:
builder.Services.AddSingleton<AResolver>();