【发布时间】:2016-02-19 19:28:04
【问题描述】:
我将尝试描述一个我在工作场所经常看到的问题,但我找不到解决方法或合理的解决方案。我对此进行了很多搜索,我能找到的只是我已经实现的。场景是这样的:
我有一个使用遵循存储库模式的实体框架的 ASP.NET MVC 应用程序。我将使用一个简单的学生/教师数据库结构来举例说明
实体
public class Student : BaseEntity
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
public Teacher Tutor { get; set; }
}
public class Teacher : BaseEntity
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Student> Students { get; set; }
}
public class BaseEntity
{
public byte State { get; set; }
public Datetime CreateDate { get; set; }
public Datetime UpdateDate { get; set; }
}
现在,假设我需要公开一个方法来返回学生姓名列表及其教师姓名:
var students = context.Students.Include(x => x.Teacher).ToList();
上面的查询很糟糕,我们都知道,因为它返回所有列。现在,如果我们重构这个:
var students = context.Students.Include(x => x.Teacher)
.Select(x => new
{
Name = x.Name,
TeacherName = x.Teacher.Name
}).ToList();
我将有一个只选择我想要的字段的高性能查询。那挺好的。但现在我需要做出选择。要将此列表返回给我的控制器,我可以:创建一个 StudentDTO,或仅使用我在查询中选择的列填充一个 Student 实例。
DTO 方法
如果我创建一个 DTO 并将其传递给我的控制器,一切都会“很好”。不用担心多余的字段。
返回 EF 实体学生
如果我将数据库实体按原样返回到我的控制器,即使我只加载了我想要的字段,我也会得到所有其他空字段。所以我创建了一个 ViewModel 来只返回我想要的数据。 (这是我们现在与 AutoMapper 一起在大多数方法中所做的)
问题:
看到模式了吗?无论哪种方式,我最终都会创建一个类来映射我的回报。大多数时候我都很好,但是在我现在正在工作的项目中,我们有几种方法可以公开,并且每种方法都有不同的返回结构。例如,如果我想返回只包含学生 ID 和姓名的学生列表怎么办?创建另一个 DTO 或 ViewModel?
该项目有一个由 5 名开发人员组成的团队,并且 ViewModel 文件夹中塞满了类。当方法返回非常具体时,我开始指示他们在控制器内返回一个匿名对象。我现在只在确定可以在其他地方重复使用时才创建视图模型。
但是这种匿名方法也变得很糟糕,因为现在我必须在几个控制器中这样做,而且我觉得我在重复自己。
还有其他方法可以解决这个问题吗?当然,我正在谈论的项目比这个例子复杂得多,有几个实体和相当复杂的查询。我觉得这在其他项目中经常发生,我没能找到一个像样的出路。
【问题讨论】:
-
为什么使用空字段的 DTO 方法不行?
-
使用 DTO 我不会有空字段。如果我返回我的数据库实体,我将得到空字段。看到基类了吗?我的客户端不需要状态和其他东西。问题是每次我需要以不同的方式返回数据时,我发现继续创建新类(DTO 或 ViewModel)效率非常低。
标签: asp.net-mvc entity-framework dto asp.net-mvc-viewmodel