Reputation: 659
I am using automapper in c#.
class A
{
public int Value { get; set; }
public string Code { get; set; }
public B? Details { get; set; }
}
class B
{
public int Id { get; set;}
public string Name { get; set; }
}
class C
{
public int Value { get; set; }
public string Code { get; set; }
public int? DetailId { get; set; }
public string? DetailName { get; set; }
}
And in automapper I used like below:
CreateMap<C, A>()
.ForPath(o => o.Details.Id, b => b.MapFrom(z => z.DetailId))
.ForPath(o => o.Details.Name, b => b.MapFrom(z => z.DetailName))
.ReverseMap();
When I using like the above mapping, I get like output as
"details ": {
"id": 0,
"name": ""
}
I need to get Details
value as null instead of an object type if it's members have no value. i.e) DetailId
and DetailName
have no value. How to get this?
"details" : null
Upvotes: 2
Views: 1753
Reputation: 1024
You can user Conditional Mapping
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<C, B>()
.ForMember(o => o.Id, b => b.MapFrom(z => z.DetailId))
.ForMember(o => o.Name, b => b.MapFrom(z => z.DetailName));
cfg.CreateMap<C, A>()
.ForMember(o => o.Details, b => b.MapFrom((c, a, obj, context) => !string.IsNullOrEmpty(c.DetailName) ? context.Mapper.Map<B>(c) : null))
.ReverseMap();
});
Upvotes: 5
Reputation: 1
You can use IValueResolver
interface to achieve what you require. Documentation: http://docs.automapper.org/en/stable/Custom-value-resolvers.html
Also there's a similar question: Automapper Mapping Multiple Properties to Single Property
Configuration:
CreateMap<C, A>()
.ForMember(o => o.Details, b => b.MapFrom<DetailsValueResolver>())
.ReverseMap();
Implementation:
// Note: this does not cover ReverseMap() when you would try to convert A to C
public class DetailsValueResolver : IValueResolver<C, A, B>
{
// Runs every time you map C to A
public B Resolve(C source, A destination, B destMember, ResolutionContext context)
{
// Covers cases where you can get null or empty DetailName, as well as null or zero DetailId
if (!string.IsNullOrEmpty(source.DetailName) && source.DetailId > 0)
{
return new B { Id = (int)source.DetailId, Name = source.DetailName };
}
return null;
}
}
You also can omit explicitly setting strings and classes as nullable types with ?
as you do here:
public B? Details { get; set; }
public string? DetailName { get; set; }
Because string
type and any class is null
by default.
Upvotes: 0
Reputation: 1970
You could do this with an AutoMapper after map action.
Something like this:
CreateMap<C, A>()
.ForPath(o => o.Details.Id, b => b.MapFrom(z => z.DetailId))
.ForPath(o => o.Details.Name, b => b.MapFrom(z => z.DetailName))
.AfterMap((src, dest) =>
{
dest.Details = src.DetailId.HasValue && src.DetailName != null
? dest.Details
: null;
})
.ReverseMap());
Upvotes: 4