C# 当外键实体的类型相同时,AutoMapper将忽略MaxDepth
我试图让AutoMapper只映射实体的第一级,所以我设置了MaxDepth(1),这非常有效,除了我的菜单实体,它有一个名为ParentMenu的属性,也是菜单类型 Startup.csC# 当外键实体的类型相同时,AutoMapper将忽略MaxDepth,c#,asp.net-core,entity-framework-core,automapper,C#,Asp.net Core,Entity Framework Core,Automapper,我试图让AutoMapper只映射实体的第一级,所以我设置了MaxDepth(1),这非常有效,除了我的菜单实体,它有一个名为ParentMenu的属性,也是菜单类型 Startup.cs public IServiceProvider ConfigureServices(IServiceCollection services) { services ... ... .AddAutoMapper(config => {
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services
...
...
.AddAutoMapper(config =>
{
config.AddProfiles(typeof(Startup).Assembly);
config.ForAllMaps((cfg, expr) =>
{
if (typeof(Entity).IsAssignableFrom(cfg.DestinationType))
{
expr.MaxDepth(1);
}
});
config.CreateMissingTypeMaps = true;
config.ValidateInlineMaps = false;
});
...
...
}
public class Menu : Entity
{
int Id {get; set;}
string Name {get; set;}
int ParentMenuId {get; set;}
Menu ParentMenu {get; set;}
int ModuleId {get; set;}
Module Module {get; set;}
}
public class MenuViewModel
{
int Id {get; set;}
string Name {get; set;}
int ParentMenuId {get; set;}
string ParentMenuName {get; set;}
int ModuleId {get; set;}
string ModuleName {get; set;}
}
public IActionResult Edit(MenuViewModel viewModel)
{
var model = EditGetModel(id); // returns the Menu Entity
Mapper.Map(viewModel, model);
// model.ParentMenuId is set properly
// model.ParentMenu set to a new instance of Menu ignoring MaxDepth(1)
// model.ModuleId is set properly
// model.Module is properly left null
...
...
}
菜单.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services
...
...
.AddAutoMapper(config =>
{
config.AddProfiles(typeof(Startup).Assembly);
config.ForAllMaps((cfg, expr) =>
{
if (typeof(Entity).IsAssignableFrom(cfg.DestinationType))
{
expr.MaxDepth(1);
}
});
config.CreateMissingTypeMaps = true;
config.ValidateInlineMaps = false;
});
...
...
}
public class Menu : Entity
{
int Id {get; set;}
string Name {get; set;}
int ParentMenuId {get; set;}
Menu ParentMenu {get; set;}
int ModuleId {get; set;}
Module Module {get; set;}
}
public class MenuViewModel
{
int Id {get; set;}
string Name {get; set;}
int ParentMenuId {get; set;}
string ParentMenuName {get; set;}
int ModuleId {get; set;}
string ModuleName {get; set;}
}
public IActionResult Edit(MenuViewModel viewModel)
{
var model = EditGetModel(id); // returns the Menu Entity
Mapper.Map(viewModel, model);
// model.ParentMenuId is set properly
// model.ParentMenu set to a new instance of Menu ignoring MaxDepth(1)
// model.ModuleId is set properly
// model.Module is properly left null
...
...
}
MenuViewModel.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services
...
...
.AddAutoMapper(config =>
{
config.AddProfiles(typeof(Startup).Assembly);
config.ForAllMaps((cfg, expr) =>
{
if (typeof(Entity).IsAssignableFrom(cfg.DestinationType))
{
expr.MaxDepth(1);
}
});
config.CreateMissingTypeMaps = true;
config.ValidateInlineMaps = false;
});
...
...
}
public class Menu : Entity
{
int Id {get; set;}
string Name {get; set;}
int ParentMenuId {get; set;}
Menu ParentMenu {get; set;}
int ModuleId {get; set;}
Module Module {get; set;}
}
public class MenuViewModel
{
int Id {get; set;}
string Name {get; set;}
int ParentMenuId {get; set;}
string ParentMenuName {get; set;}
int ModuleId {get; set;}
string ModuleName {get; set;}
}
public IActionResult Edit(MenuViewModel viewModel)
{
var model = EditGetModel(id); // returns the Menu Entity
Mapper.Map(viewModel, model);
// model.ParentMenuId is set properly
// model.ParentMenu set to a new instance of Menu ignoring MaxDepth(1)
// model.ModuleId is set properly
// model.Module is properly left null
...
...
}
MenuController.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services
...
...
.AddAutoMapper(config =>
{
config.AddProfiles(typeof(Startup).Assembly);
config.ForAllMaps((cfg, expr) =>
{
if (typeof(Entity).IsAssignableFrom(cfg.DestinationType))
{
expr.MaxDepth(1);
}
});
config.CreateMissingTypeMaps = true;
config.ValidateInlineMaps = false;
});
...
...
}
public class Menu : Entity
{
int Id {get; set;}
string Name {get; set;}
int ParentMenuId {get; set;}
Menu ParentMenu {get; set;}
int ModuleId {get; set;}
Module Module {get; set;}
}
public class MenuViewModel
{
int Id {get; set;}
string Name {get; set;}
int ParentMenuId {get; set;}
string ParentMenuName {get; set;}
int ModuleId {get; set;}
string ModuleName {get; set;}
}
public IActionResult Edit(MenuViewModel viewModel)
{
var model = EditGetModel(id); // returns the Menu Entity
Mapper.Map(viewModel, model);
// model.ParentMenuId is set properly
// model.ParentMenu set to a new instance of Menu ignoring MaxDepth(1)
// model.ModuleId is set properly
// model.Module is properly left null
...
...
}
我不明白当一个实体具有相同类型的属性时,为什么会忽略MaxDepth(1),如果有任何帮助,我将不胜感激。这似乎与深度或递归无关。确切的问题是什么也不清楚。您拥有的代码是将视图模型映射到实体上。如果我不得不猜测的话,我会想象问题是AutoMapper正在创建一个新的
菜单
实例,并用它替换实体上现有的父菜单
属性。原因是您正在投影ParentMenuName
,它将映射到实体上的ParentMenu.Name
。您应该忽略映射中的父菜单:
CreateMap<MenuViewModel, Menu>()
...
.ForMember(dest => dest.ParentMenu, opts => opts.Ignore());
CreateMap()
...
.FormMember(dest=>dest.ParentMenu,opts=>opts.Ignore());
MaxDepth(1)对模块属性的作用与预期的一样,只是当属性的类型和映射的实体相同时,它就不起作用了。关键是,您没有映射任何会导致任何类型的递归甚至一开始就有关系的东西。您的视图模型是一个100%平面模型,与任何其他模型都不相关。根据您发布的代码,视图模型是您的源代码,因此这只是一个直接的投影映射。它是指映射源对象的深度。这与目的地无关。视图模型没有标高,因此“最大深度”根本不适用于此处。正如我在回答中所说,正在创建一个新的菜单
实例,因为ParentMenuName
正在投影到ParentMenu.Name
,AutoMapper必须实例化ParentMenu
,以设置它。AutoMapper假设ParentMenuId应该映射到ParentMenu.Id,对于映射到Module.Id的ModuleId也是如此;如果我没有设置MaxDepth(1),那么ParentMenu.Id和Module.Id都会被设置;但是,当设置MaxDepth(1)时,不会设置Module.Id,因为它遵守MaxDepth(1)设置,但是,当ParentMenu.Id的行为应与模块相同时,会映射它;当属性为相同类型时,似乎存在问题。不管ViewModel是否是平面的,Automapper都会根据名称对映射进行假设;因此使用了MaxDepth(1)。未映射该Id,因为目标(ParentMenuId
)上有一个具有该名称的文本属性,因此它不需要投影到ParentMenu
。没有ParentMenuName
属性,因此它会投影到ParentMenu.Name
。最大深度与此无关。