Hi Bill,
You're skilled at discovering areas that need improvement:) There are two areas this relates to. One is a conceptual issue, the other an implementation compromise in the current tool.
The conceptual issue is that there are three types of unary fact types based on assumptions about open and closed world:
-
Closed World Unary (CW): anything not explicitly true is assumed to be false.
-
Open World Unary (OW): anything not explicitly true is assumed to be unknown, false is not allowed.
-
Open World with Negation Unary (OWN): all three values (true/false/unknown) can be stated in the model.
We will eventually add options to the unary to specify which assumption you want, but we currently map to the most flexible of these (OWN), mostly because of an internal implementation limitation.
Implementation details
Internally, the NORMA model has a fully binarized form which is used for mapping to many implementation targets (including relational). The unary is stored as a binary fact type with an implied boolean role on the right and a simple uniqueness constraint on the left (you can see this uniqueness constraint in the model browser). You can see that this pattern corresponds to OWN. Adding a mandatory makes this a closed world pattern, and adding a value constraint {true} (without the mandatory) makes this an OW pattern.
The reason that we do not currently allow the option of adding the mandatory constraint is that it conflicts with other constraints placed on the unary. For example, if you're model has 'A r' and 'A s' and you place a disjunctive mandatory across them, then a closed world assumption (with simple mandatory roles on the unary) would conflict with the disjunctive mandatory constraint. Conceptually, the disjunctive mandatory on the unaries means 'Ar is true or As is true'. However, in the binary form, it means 'Ar is populated or As is populated', where populated can be either true or false.
So, by default, constraints applied to a unary role in ORM always have a 'when true' condition, so if the role is explicitly false the constraint does not apply. Conceptually, you can think of a derived fact type for each unary that is populated only when the unary is true (but not false). In order to get the correct intepretation of constraints attached to unaries, I needed a formal notion of either derived fact type or conditional constraint, which were not available in the model when we modeled unaries. With the exception of a datatype-defined constant I can reference (true/false for boolen), all of the formal underpinnings are now in place for properly modeling these constraints. I still need to automatically generate the 'when true' conditions on constraints attached to unaries, adjust the validation rules to check for conditions on the constraints (so that the mandatories don't conflict), then add the CW/OW options to the unary fact types. Basically, we're getting closure, but appearances are deceiving, and this is a much more complicated problem that it appears on the surface.
Stopgap Solutions
If you want to generate closed world semantics, then you could fallback on a Custom Properties-based approach similar to the one I showed for generating different SQL schema names (see http://www.ormfoundation.org/forums/p/573/1706.aspx#1706). You could easily write a format modifier to look up a custom property and modify the isNullable accordingly. You can also just change the nullable property on the column, although this will change back when any significant .ORM changes are made.
-Matt