我正在使用带有nhibernate的ASP.NET MVC 2。我有这个 Sales 类。销售有很多付款。一旦销售'状态变为确认,就不应修改销售付款。我需要有关如何强制执行此操作的建议。
在尝试进行此验证时,我对几件事情感到困惑:
我应该在控制器操作中强制执行此操作吗?
答案 0 :(得分:1)
您可以通过使其受到保护甚至隐私来隐藏该集合。 NHibernate仍然会找到它。或者,当销售状态为限制值时,您可以让集合getter返回不可变集合。
private ISet<Payment> _payments;
public virtual ISet<Payment> Payments
{
get
{
if (Status == SalesStatus.Confirmed)
return new ImmutableSet<Payment>(_payments);
return _payments;
}
private set { _payments = value; }
}
在验证器中放置验证规则也没关系。您可以告诉NHibernate直接访问支持字段(如果您当前正在使用自动属性,则可能必须添加支持字段。)
<property name="_name" access="field"/>
<property name="Description" access="nosetter.camelcase-underscore"/>
编辑其他问题...
在保存之前,我不倾向于抛出异常。像在属性设置器中一样向前抛出它们可能会让UI开发人员烦恼,他们不得不一次只返回一个错误。我也主要使用MVC应用程序,所以我最近一直在使用System.ComponentModel.DataAnnotations验证属性。虽然在某些方面受到限制,但它们在MVC上可以很好地用于浏览器和控制器中的模型检查。但是,如果您使用它们,我建议您创建一个自定义拦截器,以便在保存之前检查它们。如果出现任何问题,拦截器就会抛出异常。
答案 1 :(得分:0)
有几种选择:
答案 2 :(得分:0)
我将在您的解决方案中介绍两个新项目(图层):
您的模型层应包含接口和支持类型:
public interface ISales
{
IEnumerable<IPayment> GetPayments();
}
public enum PaymentStatus
{
Unknown,
Confirmed
}
public interface IPayment
{
// your public properties
PaymentStatus Status { get; set; }
}
您应该将NHibernate类移动到服务层并使用internal
隐藏它们。您的NHibernate类实现了模型接口:
internal class Sales : ISales
{
public IEnumerable<IPayment> GetPayments()
{
// your implementation
}
}
internal class Payment : IPayment
{
// your public properties
public PaymentStatus Status { get; set; }
}
public class SalesService
{
public ISales FindByKey(int key)
{
// your implementation
}
public void AddPayment(ISales sales, IPayment payment)
{
// throw exception if validation fails
}
public void DeletePayment(ISales sales, IPayment payment)
{
// throw exception if validation fails
}
}
public class PaymentService
{
public IPayment FindByKey(int key)
{
// your implementation
}
}
由于隐藏了类Sales
和Payment
,因此您的控制器需要使用服务类:
public class SalesController : Controller
{
private readonly SalesService salesService;
private readonly PaymentService paymentService;
public SalesController()
{
salesService = new SalesService();
paymentService = new PaymentService();
}
public ActionResult AddPayment(int salesId, int paymentId)
{
var sales = salesService.FindByKey(salesId);
var payment = paymentService.FindByKey(paymentId);
salesService.AddPayment(sales, payment);
return RedirectToAction("Index");
}
}
您还应考虑使用IoC container或autofac等Ninject。