Model 和 ViewModel 代表不同的关注点。将它们分开。实体应该反映数据状态,您可以在其中定义视图模型以支持不同的视图关注点。当您通过实体从 EF 上下文加载视图模型时,您使用.Select(),它将为您的视图模型需要的列组成高效的 SQL 查询。
例如,如果我有一个定义了 20 多个属性的帐户实体,但我想提供一个帐户列表,其中仅列出他们的用户名、上次登录时间和角色列表:(这将是“名称" 由 AccountRoles 表引用的 Role 的属性,该表在帐户和角色之间链接多对多)
[Serializable]
public class AccountSummaryViewModel
{
public string AccountName { get; set; }
public DateTime LastLoginDateTime { get; set; }
public ICollection<string> Roles { get; set; } = new List<string>();
}
var accounts = MyContext.Accounts
.Where(x => x.IsActive)
.OrderBy(x => x.AccountName)
.Select(x => new AccountSummaryViewModel
{
AccountName = x.AccountName,
LastLoginDateTime = x.LastLoginDateTime,
Roles = x.Roles.Select(x => x.Role.Name).ToList()
}).ToList();
实体结构反映了您的数据结构,但是当服务器去查询这些实体以提供视图时,请为您要显示的数据结构定义 ViewModel 并利用 EF 组合查询来填充该视图模型。
您还可以利用 Automapper 的 .ProjectTo<T>() 方法来实现此目的,该方法与 EF 的 IQueryable 实现集成。
EF DbContexts 也只能注册一个与单个表关联的实体。要让多种类型的实体指向一个 Account 表,您需要多个 DbContext 定义。有界上下文对大型系统很有用,但如果使用不当,可能会导致上下文引用错综复杂。
建议避免将实体传递给视图,因为这可能会导致各种性能问题、异常以及安全漏洞,尤其是当控制器操作接受来自客户端的实体时。通过将实体传递给客户端服务向客户端传递的信息比它需要的多,并且您会遇到触发延迟加载调用或使用循环引用使序列化出错的潜在问题。该系统还告诉黑客/竞争对手更多关于你的数据结构和数据的信息,而不是实际应该的。 UI 可能不会显示实体中的大部分信息,但它会将所有这些数据发送到客户端。这需要服务器/客户端上更多的内存,以及更大的网络负载。