.NET Core 2中API项目ViewModel绑定DAL项目POCO类的方案问询
嘿,这个问题我熟,我来给你捋清楚!
首先咱们先搞明白脚手架报错的原因:你用的是「基于实体框架的API控制器」模板对吧?这个工具默认会把你选的模型当成EF实体,自动尝试关联到DbContext里的DbSet,但你的ViewModel根本不是数据库实体,自然找不到对应的DbSet,所以就报错了。
解决方案步骤
1. 放弃自动脚手架,手动创建空API控制器
别再用那个带EF的模板了,直接选「空API控制器」,自己写业务逻辑就行。这样就能完全避开脚手架强制关联DbContext的问题。
2. 手动实现POCO到ViewModel的映射(不用AutoMapper)
既然不想用AutoMapper,咱就自己写映射逻辑,两种简单方式:
- 给ViewModel加实体构造函数:
// 你的ViewModel public class MediumViewModel { // 只保留需要暴露给API的字段 public int Id { get; set; } public string MediumName { get; set; } // 其他你想展示的属性... // 接收Medium实体的构造函数 public MediumViewModel(Medium medium) { Id = medium.Id; MediumName = medium.Name; // 逐个映射需要的字段 } } - 写扩展方法:
public static class MediumExtensions { public static MediumViewModel ToViewModel(this Medium medium) { return new MediumViewModel { Id = medium.Id, MediumName = medium.Name }; } }
3. 在控制器里实现业务逻辑
注入你的DbContext,查询实体后转成ViewModel返回:
[Route("api/[controller]")] [ApiController] public class MediumController : ControllerBase { private readonly MyDbContextClass _context; public MediumController(MyDbContextClass context) { _context = context; } [HttpGet] public async Task<IActionResult> GetAllMediums() { // 正常查询POCO,LINQ不受影响(因为属性还是public) var mediums = await _context.Mediums.ToListAsync(); // 转成ViewModel var viewModels = mediums.Select(m => new MediumViewModel(m)).ToList(); return Ok(viewModels); } // POST/PUT逻辑同理:接收ViewModel,转成POCO再操作数据库 [HttpPost] public async Task<IActionResult> CreateMedium(MediumViewModel viewModel) { if (!ModelState.IsValid) { return BadRequest(ModelState); } // ViewModel转POCO var medium = new Medium { Name = viewModel.MediumName, // 其他字段映射 }; _context.Mediums.Add(medium); await _context.SaveChangesAsync(); // 返回带ID的ViewModel return CreatedAtAction(nameof(GetAllMediums), new { id = medium.Id }, new MediumViewModel(medium)); } }
为什么这是最佳方案?
- 完全解耦:DAL层的POCO和API层的ViewModel彻底分开,POCO不用加任何Web相关属性(比如
JsonIgnore),保持纯粹的数据库模型。 - 精准控制:ViewModel只包含需要暴露的字段,自动避开了那些不想展示的关联属性,
ModelState.IsValid验证也只会针对ViewModel里的属性,完美解决你的验证问题。 - 不影响LINQ:POCO的关联属性还是
public,查询时Include/Join等操作完全正常,不会像设成internal那样受限。
替代方案(如果暂时不想用ViewModel)
如果你只是想快速解决暴露和验证问题,也可以给POCO的关联属性加两个特性:
public class Medium { public int Id { get; set; } public string Name { get; set; } // 序列化时忽略,API返回不展示 [JsonIgnore] // 模型绑定时忽略,不会触发ModelState验证 [BindNever] public Hold Hold { get; set; } [JsonIgnore] [BindNever] public InExMedium InExMedium { get; set; } }
但这个方案有个缺点:POCO里加了ASP.NET Core的特性,导致DAL层依赖Web层,违反了分层架构的原则,所以还是ViewModel方案更推荐。
内容的提问来源于stack exchange,提问作者Nicolas
相关产品推荐
相关产品推荐

