Mapping to nested properties #343
-
I'm using AutoMapper to do the usual mapping of business objects (BOs) to data transfer objects (DTOs) Now I need to do the reverse mapping (DTOs to BOs) The problem that I'm facing is that // from
class FooDto {
title: string
barIds: number[]
}
// to
class CreateFooBo {
foo: {
title: string
}
bar: {
barIds: number[]
}
} where Can we do this kind of mapping without doing it manually for each prop?I think I can make one solution using
For now, I have two mappings. One that extracts the Manually I can do this (using a real example in some Nestjs project):export class CreateWorkDto {
title: string;
description: string;
type: WorkType;
weight: number;
start: Date;
end: Date;
languageId: number;
classId: number;
allowedUsersIds: number[];
forkedFromId?: number;
}
// ...
class CreateWorkBo {
work: {
institutionOwner: number;
title: string;
markdownDescription: string;
type: WorkType;
weight: number;
languageVersion: string;
start: string;
end: string;
languageId: number;
classId: number;
forkedFromId?: number;
}
user: {
allowedUsersIds: number[];
}
}
// ...
mapper
.createMap(CreateWorkDto, CreateWorkBo)
.forMember(d => d.user.allowedUsersIds, mapFrom(s => s.allowedUsersIds))
// .forMember(d => d.work.institutionOwner, /* retrived using mapWithArguments */)
.forMember(d => d.work.title, mapFrom(s => s.title))
.forMember(d => d.work.markdownDescription, mapFrom(s => s.description))
.forMember(d => d.work.type, mapFrom(s => s.type))
.forMember(d => d.work.weight, mapFrom(s => s.weight))
// .forMember(d => d.work.languageVersion, /* */)
.forMember(d => d.work.start, mapFrom(s => formatAsISODate(s.start)))
.forMember(d => d.work.end, mapFrom(s => formatAsISODate(s.end)))
.forMember(d => d.work.classId, mapFrom(s => s.classId))
.forMember(d => d.work.languageId, mapFrom(s => s.languageId))
.forMember(d => d.work.forkedFromId, mapFrom(s => s.forkedFromId))
// .. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
There are two approaches:
class CreateWorkBo {
work: {
institutionOwner: number;
title: string;
markdownDescription: string;
type: WorkType;
weight: number;
languageVersion: string;
start: string;
end: string;
languageId: number;
classId: number;
forkedFromId?: number;
}
user: {
allowedUsersIds: number[];
}
} becomes class CreateWorkBoWork {
institutionOwner: number;
title: string;
markdownDescription: string;
type: WorkType;
weight: number;
languageVersion: string;
start: string;
end: string;
languageId: number;
classId: number;
forkedFromId?: number;
}
class CreateWorkBo {
work: CreateWorkBoWork;
user: {
// I keep this the same since it only has 1 property in this example. If it makes sense to make a model, do the same as "work"
allowedUsersIds: number[];
}
} then you would have: mapper.createMap(CreateWorkDto, CreateWorkBoWork)
.forMember(d => d.markdownDescription, mapFrom(s => s.description))
.forMember(d => d.start, mapFrom(s => formatAsISODate(s.start)))
.forMember(d => d.end, mapFrom(s => formatAsISODate(s.end)));
mapper.createMap(CreateWorkDto, CreateWorkBo)
.forMember(d => d.work, mapWith(CreateWorkBoWork, CreateWorkDto, s => s))
.forMember(d => d.work.institutionOwner, mapWithArguments(/*..*/))
/* .forMember(d => d.work.languageVersion) */
.forMember(d => d.user.allowedUsersIds, mapFrom(s => s.allowedUsersIds)) This first approach sticks with AutoMapper concept. Everything should be a class/model. And you can control the naming conventions as well
mapper
.createMap(CreateWorkDto, CreateWorkBo)
.forMember(
(d) => d.work,
// this can totally be extracted out to a utility function
mapWithArguments(
(
{
title,
description,
type,
weight,
start,
end,
classId,
languageId,
forkedFromId,
},
extraArguments
) => ({
title,
markdownDescription: description,
institutionOwner: extraArguments,
type,
weight,
start: formatAsISODate(start),
end: formatAsISODate(end),
classId,
languageId,
forkedFromId,
})
)
)
.forMember(
(d) => d.user,
mapFrom(({ allowedUsersIds }) => ({ allowedUsersIds }))
) Would these two approaches be able to solve your problem> |
Beta Was this translation helpful? Give feedback.
There are two approaches:
CreateWorkBo#work
andCreateWorkBo#user
?becomes