在 AutoMapper ForMember 映射中重用代码
Reuse code in AutoMapper ForMember mappings
我正在研究 Entity Framework Core
和 AutoMapper
(版本 9)的解决方案。
从我的实体 classes 到 DTO 的映射是通过投影完成的。
var dto = await context.Companies
.ProjectTo<MyDto>(config, new { departmentName = "Sales" });
在映射中,我select某个部门。
public class MyProfile : Profile
{
public MyProfile()
{
string departmentName = null;
CreateMap<Company, MyDto>()
.ForMember(m => m.DepartmentLocation, opt => opt.MapFrom(src =>
src.Divisions.SelectMany(dv =>
dv.Departments.Where(d => d.Name == departmentName)
)
.Single().Location));
}
}
是否可以将代码移动到 select 部门到配置文件 class 中的另一个(私有)方法?
映射其他 DTO 成员时也需要此代码。
我试图将代码移动到另一个方法,但是没有填充公司的部门集合。可能是因为 EF 无法将方法转换为 SQL。我还尝试将方法重写为 returns 一个部门的 Func 表达式,但是我不能直接使用结果来访问映射中的部门属性。
public class MyProfile : Profile
{
public MyProfile()
{
string departmentName = null;
CreateMap<Company, MyDto>()
.ForMember(m => m.DepartmentLocation, opt => opt.MapFrom(src =>
SelectDepartment(src, departmentName).Location)
);
}
private Department SelectDepartment(Company company, string departmentName)
{
var department = company.Divisions
.SelectMany(Departments.Where(d => d.Name == departmentName)
.First();
if (department == null)
throw new AutoMapperMappingException($"Department '{departmentName}' not found!");
return department;
}
}
有什么建议吗?
这对你来说是一半的解决方案,但无论如何我都会post。您可以通过创建提供表达式的方法来完成映射。问题是——如果没有找到试衣部门如何抛出异常,因为你不能在表达式中抛出异常。我的建议是在映射之后抛出异常,因为无论如何您都必须查询数据。
public class MyMappingProfile : Profile
{
public MyMappingProfile()
{
string departmentName = "Foo";
CreateMap<Company, MyDto>()
.ForMember(m => m.DepartmentLocation, opt => opt.MapFrom(SelectDepartment(departmentName)));
}
private Expression<Func<Company, string>> SelectDepartment(string departmentName)
=> (company) => company.Divisions
.SelectMany(division => division.Departments)
.Where(department => department.Name == departmentName)
.FirstOrDefault()
.Location;
}
EF Core 将生成很好的查询:
SELECT(
SELECT TOP(1) [d0].[Name]
FROM [Division] AS[d]
INNER JOIN [Department] AS [d0] ON [d].[Id] = [d0].[DivisionId]
WHERE ([c].[Id] = [d].[CompanyId])
AND ([d0].[Name] = @__departmentName_0))
AS [DepartmentLocation]
FROM [Company] AS[c]
用法:
var result = dbContext
.Set<Company>()
.ProjectTo<MyDto>(mapperConfiguration)
.ToList();
result.ForEach(myDto =>
{
if (myDto.DepartmentLocation == null)
{
throw new AutoMapperMappingException("Department was not found!");
}
});
我正在研究 Entity Framework Core
和 AutoMapper
(版本 9)的解决方案。
从我的实体 classes 到 DTO 的映射是通过投影完成的。
var dto = await context.Companies
.ProjectTo<MyDto>(config, new { departmentName = "Sales" });
在映射中,我select某个部门。
public class MyProfile : Profile
{
public MyProfile()
{
string departmentName = null;
CreateMap<Company, MyDto>()
.ForMember(m => m.DepartmentLocation, opt => opt.MapFrom(src =>
src.Divisions.SelectMany(dv =>
dv.Departments.Where(d => d.Name == departmentName)
)
.Single().Location));
}
}
是否可以将代码移动到 select 部门到配置文件 class 中的另一个(私有)方法?
映射其他 DTO 成员时也需要此代码。
我试图将代码移动到另一个方法,但是没有填充公司的部门集合。可能是因为 EF 无法将方法转换为 SQL。我还尝试将方法重写为 returns 一个部门的 Func 表达式,但是我不能直接使用结果来访问映射中的部门属性。
public class MyProfile : Profile
{
public MyProfile()
{
string departmentName = null;
CreateMap<Company, MyDto>()
.ForMember(m => m.DepartmentLocation, opt => opt.MapFrom(src =>
SelectDepartment(src, departmentName).Location)
);
}
private Department SelectDepartment(Company company, string departmentName)
{
var department = company.Divisions
.SelectMany(Departments.Where(d => d.Name == departmentName)
.First();
if (department == null)
throw new AutoMapperMappingException($"Department '{departmentName}' not found!");
return department;
}
}
有什么建议吗?
这对你来说是一半的解决方案,但无论如何我都会post。您可以通过创建提供表达式的方法来完成映射。问题是——如果没有找到试衣部门如何抛出异常,因为你不能在表达式中抛出异常。我的建议是在映射之后抛出异常,因为无论如何您都必须查询数据。
public class MyMappingProfile : Profile
{
public MyMappingProfile()
{
string departmentName = "Foo";
CreateMap<Company, MyDto>()
.ForMember(m => m.DepartmentLocation, opt => opt.MapFrom(SelectDepartment(departmentName)));
}
private Expression<Func<Company, string>> SelectDepartment(string departmentName)
=> (company) => company.Divisions
.SelectMany(division => division.Departments)
.Where(department => department.Name == departmentName)
.FirstOrDefault()
.Location;
}
EF Core 将生成很好的查询:
SELECT(
SELECT TOP(1) [d0].[Name]
FROM [Division] AS[d]
INNER JOIN [Department] AS [d0] ON [d].[Id] = [d0].[DivisionId]
WHERE ([c].[Id] = [d].[CompanyId])
AND ([d0].[Name] = @__departmentName_0))
AS [DepartmentLocation]
FROM [Company] AS[c]
用法:
var result = dbContext
.Set<Company>()
.ProjectTo<MyDto>(mapperConfiguration)
.ToList();
result.ForEach(myDto =>
{
if (myDto.DepartmentLocation == null)
{
throw new AutoMapperMappingException("Department was not found!");
}
});