代码之家  ›  专栏  ›  技术社区  ›  Endy Tjahjono

更改对象子对象的验证放在哪里?

  •  0
  • Endy Tjahjono  · 技术社区  · 15 年前

    我使用的是带有nhibernate的ASP.NET MVC 2。我有这个 销售额 上课。销售有很多 付款 . 一旦Sales状态变为 已确认 . 我需要关于如何执行的建议。

    当我试图证明这一点时,有几件事让我困惑:

    • 添加和删除付款:
      • 我可以创造 追加付款 删除付款 方法,但每个人都必须记住使用这些方法,而不是直接添加和删除付款集合
      • 我不想隐藏付款集合,因为nhibernate需要它,而且这个集合也用于软件的其他部分
    • 修改现有付款方式:
      • 我不认为我应该把验证放在支付设置器中,因为nhibernate需要访问设置器。
    • 我应该抛出异常吗?有一个 discussion 关于引发异常以防止对象进入无效状态的缺点。在我的情况下,修改后的对象状态可能仍然有效,但我想阻止修改。在这种情况下抛出异常是否合理?有哪些选择?

    我应该在控制器操作中强制执行吗?

    3 回复  |  直到 9 年前
        1
  •  1
  •   Adam Boddington    15 年前

    你可以通过保护甚至私有化来隐藏收藏。尼伯纳特还是会找到的。或者,可以让集合getter在sales状态为restricted值时返回一个不可变的集合。

    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; }
    }
    

    把验证规则放在setters中也可以。您可以告诉NHibernate直接访问backing字段(如果您当前正在使用auto属性,则可能需要添加backing字段)。

    <property name="_name" access="field"/>
    <property name="Description" access="nosetter.camelcase-underscore"/>
    

    为附加问题编辑。。。

    我一般不会在保存之前抛出异常。像在属性设置器中一样,较早地抛出它们可能会让UI开发人员感到恼火,因为他们必须一次只返回一个错误。我也主要使用MVC应用程序,所以最近一直在使用System.ComponentModel.DataAnnotations验证属性。虽然在某些方面受到限制,但它们在浏览器和控制器中可以很好地与MVC一起用于模型检查。但是,如果您使用它们,我建议您创建一个自定义拦截器,以便在保存之前检查它们。拦截器是我将抛出一个异常,如果有什么是错误的。

        2
  •  0
  •   Shiraz Bhaiji    15 年前

    有几种选择:

    • 一个是在数据库中有一个触发器,那么你100%肯定
    • 你的AddPayment和DeletePayment建议,再加上一些代码检查可能是最好的方法。
        3
  •  0
  •   sheikhomar    15 年前

    我将在您的解决方案中介绍两个新项目(层):

    • 模型层
    • 服务(或业务)层

    模型层应包含接口和支持类型:

    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 .