如果域对象被允许暂时无效,那怎么决定影响验证技术?对象、技术

2023-09-03 00:12:59 作者:対着迗悾、說愛你

我在写基于MVVM一个VB.NET WinForms项目(使用绑定的WinForms)。我的直觉是,绝不允许一个域实体处于无效状态。这就要求我做的验证检查,在构造新的实体,并在每一个二传手的现有实体:

I'm writing a VB.NET Winforms project based on MVVM (using Winforms binding). My instinct is to never allow a domain entity be in an invalid state. This requires that I do validation checks in the constructor for new entities and in each setter for existing entities:

Public Class Product


    Public Sub New(ProductID as Integer, Name as String)

        If ProductID > 0 AndAlso Name.Length > 5 Then

            _ProductID = ProductID
            _Name = Name

        Else
            Throw New InvalidProductException
        End If
    End Sub

    Private _ProductID as Integer
    Public Property ProductID as Integer

        Set(value as String)

            If value > 0 then
                _ProductID = value
            Else
                Throw New InvalidProductException
            End If

        End Set

    End Property

    'Same principle as above for Name setter.


End Class

然后我跑过数据注释,这似乎pretty的光滑。我注意到,使用数据注释大多数人允许域的实体变为暂时无效,并确认该实体在某个稍后通过调用Validate.ValidateObject。至此实体无效,原始状态已丢失,除非你有一些其他的机制来回滚。

Then I ran across Data Annotations, which seemed pretty slick. I noticed that most people using Data Annotations allow the domain entity to become invalid temporarily, and then validate the entity at some later point with a call to Validate.ValidateObject. By this point the entity is invalid and the original state has been lost unless you have some other mechanism to roll it back.

两个问题:

1)是否允许域实体会暂时失效?

1) Do you allow domain entities to become temporarily invalid?

2)根据你的答案#1,你用什么技术来验证实体?

2) Based on your answer to #1, what techniques do you use to validate the entity?

推荐答案

没有,在我看来域的实体不应该被允许为无效,即使是暂时的。问题是,如果你让域无效,就像你在你的问题描述,它变得很难引进新的规则复杂性的增长。例如,你允许实体是无效的,由于某些属性,假定它稍后将验证。但在此之前发生的人增加了一个规则,即改变其结果按照同一个属性 - 你怎么知道如果规则正确的行为?你不知道。相信我,它往往发生在一些非平凡的领域。

No, in my opinion domain entities should never be allowed to be invalid, even temporarily. The problem is that it if you allow the domain to be invalid, just like you described in your question, it gets difficult to introduce new rules as complexity grows. For example you allow entity to be invalid due to some attribute, assuming that it will be validated later. But before that happens someone adds another rule, that varies its result in accordance to the same attribute - how do you know if the rule behaves correctly? You don't. Believe me, it happens quite often in non trivial domains.

的另一个原因,也没有让状态是无效的是,在某些情况下也可能会引入问题奥姆斯 - 我亲眼见到涉及NHibernate的缓存和子实体是无效的,但不知何故仍保持在高速缓存中的一个问题,我可以'T记得任何具体细节,但。

The other reason for nor allowing state to be invalid is that in certain scenarios it can introduce problems with ORMs - I have personally seen an issue involving NHibernate cache and sub-entities that were invalid but somehow still remained in cache, I can't recall any specific details though.

我倾向于使用的验证规则和验证结果基础的技术。总之,大多数对实体的方法,按以下方式实现(C#,如果你不介意的话):

The technique I tend to use bases on validation rules and validation results. In short, most of the methods on entities is implemented in the following way (C#, if you don't mind):

        public virtual void ChangeClaimEventDate(DateTimeOffset newDate)
        {
            var operationResult = ValidatorOf<Claim>
                .Validate()
                .WithCriticalRuleOf<EventDateFallsIntoPolicyCoverage>().WithParam(newDate)
                .WithCriticalRuleOf<EventDateFallsIntoInsuredCoverage>().WithParam(newDate)
                .WithCriticalRuleOf<PerformedServicesAreAvailableOnEventDate>().WithParam(newDate)
                .WithCriticalRuleOf<EventDateCannotBeChangedForBilledClaim>().WithParam(newDate)
                .ForOperation(this);

            if (operationResult.OperationFailed)
            {
                throw new InvalidBusinessOperation(operationResult);
            }

            SomeDate = newDate;
        }

关于本code最重要的事情,是该实体被改变甚至在一定的验证规则进行检查。这个例子显示的结果集的使用,因为很多时候我需要提供,即使成功了(换句话说,我有失败,其信息已被证明是用户验证有关验证信息;但是域实体仍然有效

The most important thing about this code, is that certain validation rules are checked even before the entity is changed. This example shows usage of result sets, as very often I need to provide information about validation even if it succeeds (in other words, I have validations that fail and information about it has to be shown to user; however the domain entities are still valid.

OperationResultSet ValidatorOf 是pretty的简单的基础设施类,允许轻松添加新的验证用流利的接口。该验证器实现为类实施 IValidator 接口,允许执行pretty的复杂的验证规则,很容易对它们进行测试单独为好。

The OperationResultSet and ValidatorOf are pretty simple infrastructure classes that allow adding new validators easily with fluent interface. The validators are implemented as classes implementing IValidator interface, which allows implementation of pretty complex validation rules and it is easier to test them individually as well.

我的观点是,应该验证之前进行更改域实体进行 - 用正确的约定,有些基础设施甚至简化了code结构

My point is, that validation should be performed before the changes to domain entities are performed - with the right convention and some infrastructure it even simplifies the code structure.

编辑备注:由于对这个答案有些批评的声音,我决定改变样品code一抛出返回结果的异常来代替。虽然我仍然认为这是要走的路我这种情况下,我同意,如果没有指定完整的上下文,这可能会引起误解 - 例外应该是确实的第一个选项,其他因素应该存在选择的替代品。

Edit note: due to some critical voices for this answer, I've decided to change the sample code to one that throws an Exception instead of returning results. Although I still believe that it is the way to go for my kind of scenarios, I agree that without specifying full context this might be misleading - the Exceptions should be indeed the first option and additional factors should exist to choose alternatives.