问题不在于if。有时您必须根据模型的某些方面以不同的方式呈现事物。 “问题”是Salary > 20000“逻辑”。虽然您给出的示例可能很简单,以至于它并不是非常重要,但理想情况下,这种事情并不真正属于视图。
执行此操作的标准方法是使用ViewModel。该对象的存在是为了将视图与数据模型的实现细节分离,并封装一些表示层逻辑。如果您的数据模型是例如一个实体框架代理,它有很多约束和行为,迫使它为你的表示层变成错误的“形状”。在这个特定的例子中,你的ViewModel 可能有一个类似于bool ShowHighSalarySection 的属性——要么由ViewModel 计算,要么由一些外部业务代码计算并存储在ViewModel 中。
ViewModel 的精确形状很大程度上取决于您所遵循的 MV* 的特定风格,但例如:-
- 带有数据模型构造函数的简单
ViewModel:-
public class EmployeeViewModel
{
private readonly Employee model;
public EmployeeViewModel(Employee model)
{
this.model = model;
}
public bool ShowHighSalarySection { get { return this.model.Salary > 20000; } }
// Some people like to have the ViewModel explicitly only expose
// the data the view needs.
public string EmployeeName { get { return this.model.EmployeeName; } }
public string Address { get { return this.model.Address; } }
public DateTime DateOfBirth { get { return this.model.DateOfBirth } }
public int Salary { get { return this.model.Salary; } }
// Or, if boilerplate freaks you out, and you don't have the tools
// to automate it, you can even just expose the data model and its
// properties directly as e.g. Model.Employee.EmployeeName.
// This gives you some abstraction very cheaply, but obviously
// still leaves your views somewhat coupled to your data model:-
public Employee Employee { get { return this.Model; } }
}
然后在你看来:-
if (Model.ShowHighSalarySection) { ...
- 您还可以使用更“愚蠢”的
ViewModel 以及AutoMapper 等映射器:-
public class EmployeeViewModel
{
// Note that this ViewModel doesn't even know the data model *exists*!
public string EmployeeName { get; set; }
public string Address { get; set; }
public DateTime DateOfBirth { get; set; }
public int Salary { get; set; }
public bool ShowHighSalarySection { get; set; }
}
在您的控制器中:-
var query = db.Employees.Select(x => ...);
// Some people like the "magic" of a mapper, especially when
// all you're doing is reasonably "dumb" transformations.
// Some people don't like that there could be somewhat complicated
// things going on behind the curtain.
// The huge advantage of this type of code is that you can usually
// leverage some kind of query projection and have the mapping
// take place on your database, rather than pulling the entire
// entity graph into memory.
var viewModel = this.mapper.Project()
.To<EmployeeViewModel>(query)
.FirstOrDefault();
return View(viewModel);
- 有时业务规则非常复杂,您可能需要一些明确的处理代码来明确负责应用业务规则:-
public class GetEmployeeQueryHandler
{
private readonly IEmployeeStore store;
public GetEmployeeQueryHandler(IEmployeeStore store)
{
this.store = store;
}
public EmployeeViewModel Handle(EmployeeQuery query)
{
var employee = store.Get(EmployeeQuery.Identity);
var viewModel = new EmployeeViewModel()
{
// Could leverage some automatic mapping to do the
// "dumb" part of the mapping if you want tidiness
// or query projection.
}
// This is probably excessive for a calculation as simple
// as this one, but we've managed to separate ourselves
// totally from both the database *and* the rendering
// engine.
// This lets us e.g. test our important business logic in
// complete isolation, or reuse it elsewhere.
viewModel.ShowHighSalarySection = employee.Salary > store.HighSalaryThreshold;
}
}
具体的去向取决于您的架构、您的理念以及您准备接受多少样板(或工具)以换取整洁。 ViewModel 所做的主要事情是它允许您将业务规则从视图中取出并放到适当的地方(更安全、更可测试、更可重用等)。