Conditional mandatory constraints

Conditional mandatory constraints

When modeling, I often find one or more objects which map to records having a significant number of mandatory fields. In constructing a user interface for a user to populate one of these records, there's a need to be able to save the record in a kind of "draft" mode, without all its mandatory fields being yet populated.
A similar situation arises with many kinds of state transition, not just from draft to complete, and these can sometimes be handled as subtype transitions. Simply place the conditionally-mandatory roles on a subtype, so that the supertype instance acquires a subtype instance dynamically after those roles are filled. However, this subtype approach relies on natural domain terminology to name the supertype, and doesn't work where some but not all mandatories are provided in one go.

But back to the draft situation, it's possible to add a unary "is draft", and then to define join mandatory constraints (using NORMA Pro, or using CQL) saying that the role is mandatory only if the object is not a draft. These constraints should get mapped as CHECK constraints (CHECK(field is not null or is_draft = true). However it's enough of a nuisance and is common enough to want to streamline it a bit in the modeling languages.

When developing applications using Ruby on Rails, it's common practise to simply omit the mandatory constraints, and to handle these validations in the Rails "model" (application code for the record type), but I prefer to enforce constraints in the DBMS where possible

Re: Conditional mandatory constraints

I have no answer to your question, but: I never deal with such issues in ORM. The simple reason: I use ORM for conceptual modeling, what is something different than how things are solved on implementation level.

Re: Conditional mandatory constraints

Jacob, while it may be fair to say that the constraint as I outlined it is only weakly conceptual, there are definitely other similar situations which are clearly conceptual.

For example, when an insurance claim is lodged, certain facts must all be established before the next step in the business process (appointing a loss assessor, for example) can proceed. After this step has been fulfilled, certain other facts are required before following steps, and so on. The point here is that the mandatory requirements vary depending on the step of the business process which has been reached.

It would be quite incorrect to define such dynamic constraints as non-conceptual. You might argue that the possible facts form the conceptual basis, and the various constraints follow and are subordinate; but the constraints are still fully conceptual, because they also map important rules in the business domain.

Matt's suggestion (made to me privately) is to leave the facts as non-mandatory, but to derive a unary, or a readiness fact type, from the existence of the facts that are required for a particular state to be reached, or an operation to be performed. This derived fact can then control the behaviour of the business logic, and can also be used in subset constraints to allow or prevent other situations that might occur elsewhere in the model.

NORMA Pro and my CQL language both allow the specification of such derived constraints.

Re: Conditional mandatory constraints

Honestly speaking, when I was writing my reaction, I started to write something about relevancy of this 'pattern' on business level. However I deleted it because I thought it was too 'off-topic'. So: I totally agree with you that there are similar situationson clearly conceptual levels.

What you sketch is also followed by Jan Dietz, founding father of DEMO, an approach that has an aspect model called 'Fact Model' which is inspired a lot by ORM. For example there is the object type 'Rental' with as subtypes among others 'Live Rental', 'Paid Rental', 'Ended Rental'. The solution that Dietz follows is to link a property to the reelvant subtype (e.g. 'actual rental charde' at a Paid Rental).

(If you are interested, see here (on page 26): http://www.demo.nl/publications/doc_download/122-demo-3-way-of-working.)

I think this is conceptually strong. However I step towards a practical situation may be that properties MAY be filled in certain states of an object type, but MUST be filled in others. Then you don't want to link them to the subtype.

About Matt's suggestion to derive a unary: is that to have at e.g. 'Rental' the unary 'has been started', to have certain binaries at 'Rental' and to define constraints between that binaries and the unary? Maybe you can explain this further (with a picture?).

Re: Conditional mandatory constraints

I believe this is an incorrect use of subtypes. Every instance of a subtype must be capable of playing every role of the supertype (without that role having a different meaning from the same role when applied to the supertype without reference to its subtype). In a system that models activities and lifecycles, this principle extends to requiring that every instance of a subtype must be capable of the same actions as its supertypes, and each action would have the same meaning as that action applied to an instance of the supertype (without reference to it as an instance of the subtype). These are basic requirements for Substitutivity of Individuals from the theory of types.

Accordingly, if subtypes are to be used, the basic Rental type needs to have a subtype "Promised Rental" (which contains the link to the person who made the booking, the anticipated start date/time, etc), a separate subtype StartedRental (which contains the actual start date, the nominated drivers, etc), and so on. A StartedRental is not a subtype of PromisedRental, since a Promised Rental can be started, which a StartedRental cannot. This would be a type conflict. The Rental remains a PromisedRental even after it was started (it is still the case that the Rental was once promised), so now the instance is of two subtypes as well as the supertype. This allows reference back to the nature of the promise that was made, even as that promise is being fulfilled.

However, it's not necessary to create all these subtypes. Unary (or other) roles can indicate states, and the population of other roles can be required or prevented by use of subset constraints. See the following diagram to follow this:

The unary fact types here are not derived, rather other roles are required or prevented by them. There is one important missing subset constraint which requires NORMA Pro, and doesn't fully display in ORM, which is one that requires that before a rental can be ended after the car has been picked up, the car must first be returned. This constraint requires a disjunction "either car is not picked up or car has been returned".

When I coined the term "readiness fact type", I refer to a derived unary which indicates whether all pre-conditions have been met for the object to be considered as "ready" for some other activity or roles, representing possibly a new phase of life (e.g. started, picked up, returned, etc). This is a third alternate way of working, and the one I prefer where possible (including for my original question in this thread). This is the way of working which Matt also suggested.

Note that the non-ORM shorthand shown by Jan in the objectification of a single role of the nominated-driver fact type, while I understand the intention and the meaning, is unnecessary and masks a modelling error. It is possible for any Person (whether a Driver in a Rental or not) to have a driving license. The license is not subordinate to this instance of them being nominated as a Driver in this rental situation; nor do they necessarily have another license when they are nominated in another Rental. When a person rents again, it is necessary again to check the validity of their licence, and perhaps to add new license details (since those may have changed) but the old licence is still relevant. Both old and new licences are independent of their application to a given rental. Note that in the above diagram, I have corrected this mistake with an explicit Driver subtype; though not with a fleshed-out model for licence validity over time. I've also allowed the Rental to nominate more than one driver, while still requiring that a Rental must nominate at least one driver before being started (these are both subtle changes in the business rules, which would need to ba validated with domain experts).

So to summarise, I've made a rebuttal of Jan's "way of working" from both a theoretical and practical correctness point of view, a way of correcting it (still using subtypes), and two alternative ways of working using unary fact types with subset constraints, in increasing order of preference (for this situation; I do use subtypes for such as Person/Driver, but not for phase-of-life factors as in this case).