Relationship Functionality

    In classical relational databases, the binary connection of tuples is based on the use of keys: primary and foreign. Moreover, the interpretation of this relationship is carried out outside the logical structure of the database, where it (interpretation) can be quite arbitrary in nature. Naturally, within the limits prescribed by the relational model.

    In the object paradigm, their identifiers are used to realize the connection of objects. Moreover, if the connection of objects is given a strict symmetric shape: in the form of a pair, the straight line | back link, this allows you to almost completely replace Select with natural navigation on the links. But no less important, the symmetrical form makes the connection of objects a full and independent element of the logical structure of the database, which has its own behavior and functional dependence on other existing connections.

    This article is devoted to the consideration of a wide variety of behavioral aspects of communication between objects, the implementation of which allows you to integrate a significant part of the business logic of the application directly into the logical structure of the database, thereby saving the developer from the coding routine.

    (The author allowed himself to deviate from generally accepted terminological canons, wanting to give the presentation a little more imagery).

    From an information point of view, the relationship of two objects should be understood exclusively as a mutual exchange of identifiers, according to the principle “I see you,” and nothing more. In this case, the object itself is an instance of the data class, and the connection of the class objects is the practical implementation of the rules established by the declaration of the relationship of classes - an instance of one of the four fundamental abstract entities used to model the subject area.

    Each of the classes bound by the relation takes possession of a reference attribute typed by the opposite relation class, the value of which in the class object becomes the identifier of the object of the opposite class. The class relation not only establishes the rules for connecting objects, but also serves as a natural context (transport and condition) for organizing the interaction of attributes localized in different classes.

    Relationship types


    A relation type establishes a measure of the quantitative interaction of objects derived from classes connected by a relation. As you know, there are only three options for this measure: one-to-one , many-to-one , and many-to-many .

    A many-to-one relationship , which is conveniently called a multiple relation , has a pronounced causality vector: the primary recipient of a value (link) is always a reference attribute on the many side , and the attribute value on the side is one”Will be a derived list of values ​​(links). Hence, there is often used below a terminological division attributes this attitude to attribute direct links and attribute the reverse link .

    In a completely symmetrical one-to-one relationship (it is also a unitary relation ), each of the peer reference attributes can act as the initiator of creating a connection of objects, and be the primary recipient of the value. The division into attributes of direct and reverse links in this respect is purely situational in nature. And this despite the fact that one of them will receive its value as a result of the assignment of a value to the opposite attribute.

    The conceptual meaning of the many-to-many relationship is very ambiguous, which makes it the subject of a separate consideration.

    The graphic representation of the multiple and unitary relations, which will be further used in the illustrations, looks something like this:

    This notation is used because the graphic image of the arrow is intuitively associated with both the image of the dependency vector and the image of the list attribute of the backlink. Marking a reference attribute by type and name is not a mandatory element of the image. The reference attribute is typified by the opposed relation class, and, accordingly, takes the name of this class.

    Reference connector


    The symmetry of the connection of objects is due to a causal dependence of the values ​​of the link attributes of the objects being connected. Like any other dependency, it is implemented by a connector , which we will call a reference connector . The reference connector is a priori active , which ensures permanent logical consistency and integrity of the reference values. In its work, the reference connector uses, in addition to the actual reference attributes, also the service attributes Own and Del . The multiple relationship connector declaration looks like this:
    The service attribute Own is typed by its own class, and stores the object's own identifier ( IDO ) in the class object . It is this attribute that is used by all types of relations as the source of the value transmitted by the connector of the relationship with the same linkback attribute.

    The Del service attribute is used by the relationship connector as a lock context . When a class A object is logically deleted , its Del attribute will be initialized, which will cause a call to the Unset method to the address of the base socket of the connector, which in turn will lead to a call to the address of the attribute B. {A} of the Set methodwith an "empty" value and a key, and as a result, the corresponding record will be removed from the list of backlinks B. {A}.

    The Key attribute (the key context of the connector) is the base attribute of the class by default . The value of this attribute is used by the connector as a key, in pair to the transmitted value is the IDO of the Own attribute . The backward link attribute B. {A} receiving this pair has a simple list functionality that directly forms the backlink list itself.

    Well, actually the direct link attribute A. [B] is just refThe context that provides the connector with the IDO of the target. When the attribute A. [B] receives the stored value during the implementation of the link , it calls the Reset method on the base socket of the connector , which in turn leads to the call to the address of the attribute B .. {A} of the Set method with the object IDO and key, and as a result, a new entry will be added to the list of backlinks B. {A}. Further, any subsequent change in the values ​​of the Key attributes and direct link A. [B] will be followed by successive calls to Unset and Resetwith corresponding changes to the list (s) of backlinks.

    In a unitary respect, the key context is obviously not used , but there are two link connectors that provide mirror symmetry of the implementation:
    A closer look at the presented declaration may seem that there are all the prerequisites for the looping process of assigning a reference value, but this is not so. The Set method does not generate derived recursive calls if the value received by it from the outside is equivalent to an existing one.

    Relationship Creation


    In addition to two reference attributes, at least one connector is involved in the formation of a relationship, combining a set of sockets with appropriately set flags. I want to emphasize that all this volume of declarations is hidden behind the facade of the visual designer of the data model, using the predefined methods and forms of representing the abstract meta-relation to create its instances. All that a constructor needs to create an instance of a relation is its type and descriptors of the classes to be bound.

    I also want to emphasize once again: neither the relation of classes , nor the connector of attributes , are entities of a data model, and in no way are interpreted by it. The data model operates only with classes, attributes, and sockets. Relations and connectors are the entities of the application model , which in turn is the representation (form of representation) of the data model.

    Power relationship


    Consider an operation such as transferring Goods from the Warehouse to the Warehouse : in the Transfer Invoice object, two Warehouse objects must be addressed at once . Such a need is realized by a simple increase in the power of the relation , with the replacement of the atomic form of storage of the derived values ​​of the reference attribute A. [B] by an enumerable (array).
    By increasing the power of the multiple relationship (link multiplicity), the model constructor will create an additional element for the direct link attribute, and there will be another relationship connector, similar to the existing one, which uses the new element as the source of the address pointer ( ref context). Note that the increase in power did not affect the declaration of the backward link attribute B. {A}, with the exception of adding another incoming socket. (This and subsequent figures show only contexts that are necessary in meaning).

    Similarly, an increase in the power of a unitary relation is realized.
    Since this type of relationship has additional internal symmetry, the number of elements in reference attributes on both sides of the relationship will always be the same.

    In turn, a multiple-link backlink attribute can provide more than one list. By default, the first (main) list uses the base attribute of the class as a key (for the Invoice, this will be the Date attribute ). Suppose that for some purpose you need another list with a different sort order, for example, by the amount of the Total invoice . By creating a new list declaration, the relationship constructor will create an additional element (A2) for the backlink attribute, as well as an additional reference connector. The new connector is similar to the primary, but as a key source uses not Date , and the attribute Total .
    Note and emphasize: adding a new list does not change the power of the relationship.

    If an additional logical context is specified in the list properties, then only those entries for which the context value is true will be included in it . This option will be useful, for example, when conducting “white-gray” accounting. And since all three contexts of the base link connector are already used, you can use the free lock context of one of the context sockets. For example, like this:

    As you can see, unlike ref and key contexts, a lock context can be cascaded, creating an additional logical context (condition) for an existing one.

    Referential Integrity Management


    It seems obvious that the referenced object cannot be arbitrarily deleted. Accordingly, in order to maintain referential integrity, it is necessary to control the availability of relevant external links to the object.

    As we recall, the object is logically deleted when the value of the Del service attribute is initialized . In order to provide the ability to control external links, each backlink attribute, when it is created, automatically creates a separate passive connector to the Del attribute .
    In the Set method, the specialized utility function of the Del attribute checks all incoming connectors, and as soon as one of them returns true (the list of backlinks is not empty), the functional will raise an exception aborting the transaction. But you can not bring to an exception. The Get method addressed to the Del attribute will query the connectors and return false if deleting an object is possible without conflicts.

    There are relationships that, from a conceptual point of view, are considered to be “ parental ”. For example, Invoice and its conditionally " child " Recordsthat may exist solely in the context of the Consignment Note. Here the opposite behavior is expected: the Invoice object can not only be deleted if there are backlinks from the Record objects , but it must also, in the process of its own deletion, delete all its Records . The required reaction can be provided by setting the Owner virtual flag in the relationship properties, after which the following changes will be made to the data model:


    Firstly, an active connector will be added, linking the Del attributes in the Invoice and Record classes , and secondly, by resetting the Get flag , the connector linking Del with the corresponding backlink list will be deactivated.

    Mutual relationship


    Consider a system of three classes connected by a multiple relation :


    The class object C has direct pointers to the objects B and A , object B - pointer to A . Since there are no additional rules and restrictions, objects C and B connected by a mutual reference in the most general case can consistently address different class A objects as well .

    We slightly change the example, introducing a certain semantic load into it.

    Let the C - Class is a student , Bed and - Faculty , A - university. It seems obvious that the Student is enrolled exclusively in that educational institution, at the Faculty of which specialized training takes place. In other words, for a Student, a pointer to a university is determined through a pointer to the Faculty . This rule set creation connector linking attributes direct reference to class A to class B and C through the relation CB . Let's pay attention to linking attributes are of the same type - a class A .


    The active link declaration of the reference attributes by the standard connector will automatically provide the required consistency of the reference values C. [A] = B. [A] under any external influences. Indeed:

    • upon any receipt / change of the value of C. [B], the connector will be initiated (by Unset / Reset methods ) to transfer the value of the attribute B. [A] to the attribute C. [A];
    • when the value of the attribute B. [A] changes , the new value will be transferred to all objects C from the list of backlinks B. {C};

    The declaration of the active dependence of direct link attributes C. [A] = B. [A] gives rise to a direct logical consequence:

    • in the presence of the object C the actual value C . [A] (e.g., student has chosen University Educational) domain of valid attribute values C . [B] is a list of back links attribute A . {B} (list Faculties of the University ). This corollary, in a first approximation, takes the form of a restriction, which is explicitly expressed in the data model — the automatic creation of the connector C. [B] = A. {B}, hereinafter referred to as the back- connector , derived from the direct- connector declarationC. [A] = B. [A].


    The derivative back- connector is completely passive, it is not initiated by changing the attribute C. [A], since the corresponding Unset / Reset flags of the context socket are turned off, and it does not participate in the process of processing external influences. This connector is used in the process of organizing the assignment of value to the reference attribute C. [A], which will be discussed in detail later. In the meantime, we note that a list of backlinks addressed by a back- connector, if viewed as a data source, provides many homogeneous values, without the ability to automatically select the only one from them.

    Meanwhile, there is a condition under which a strictly defined and at the same time only one element can be selected from the list. For this, the list must have the property of uniqueness by the value of the key, well, the key itself is needed.

    Group by value


    Consider an example from the same three classes, but, for greater clarity, in a slightly different interpretation: class A is a Journal whose records (class C ) should be grouped by calendar days (class B ). Each Day in the Journal is unique by the value of the Date ( D ) calendar date . This uniqueness is provided by the backlink attribute A assigned to the attribute . {B} slightly modernized list functionality that generates a transaction exception when trying to add an entry to the list with an existing key value in the list.

    The back connector has also undergone some changes: it uses the Date (D) attribute as a key context, and has become semi-active : its contexts are active (the Unset / Reset flags are set for all context socket sockets ) when the Set flag of the base socket is unchecked.


    With active context sockets, any change in the values ​​of the attributes C. [A] or C .D activates the back- connector, which will extract the value of C .D, and use it as a key when accessing the list A. {B}, after which the resulting value ( Object ID B) will be assigned to the target attribute. Thus realized the automatic positioning (aka - grouping) feature class C to class objects Bed and .

    But what happens if you enter a date for the value of C .D for which the corresponding Day object does not exist ? In this case, backThe connector will naturally return NUL, and the link to Day will be de-initialized.

    It is worth noting that this behavior is occasionally required, but more often than not, the required Day object , corresponding to the entered date, must be created automatically. To implement this behavior , the Autoset functionality is assigned to the C. [B] attribute . This functionality (discussed below), when it is initiated by the back- connector, will automatically create a new object of class B , after which it will assign the identifier of the created object as a value to the direct link attribute.

    But this is not enough. To maintain referential integrity, the attributes D and { A} New object B should automatically get a well-defined value, namely - coinciding with the current values of similar attributes of the object the C . For these purposes, in the connectors B .D → C .D and B. [A] → C. [A], the reverse transmission of the value is enabled , namely: in the incoming Get sockets of the connector belonging to the attributes C .D and C. [A] , the Set flag is additionally set . Then, when assigning a value to the attribute C. [B], - to the transport context of the connectors B .D → C .D and B. [A] → C . [A], these connectors will be initiated to transfer the values to the object B . Note that the dependency declaration shown in the diagram automatically preserves logical and referential integrity when any of the values ​​changes.

    The set of declarations considered above, which implements the grouping of objects by attribute value, is created by the model’s internal constructor in two steps. If the uniqueness option is enabled in the properties of a backlink attribute in a certain general class, then the relation to which this attribute belongs becomes unique. In this case, the target link class itself can now act as a class that groups links by the value of its base attribute. A relationship with such a class of any third class, which also has a relationship with a common class, acquires an option (in the properties dialog) that allows you to select an attribute in the tuple of the third class, by the value of which grouping is implemented.

    Link grouping


    We slightly modernize the previous example: let the place of the absolute attribute D in classes A and C take the attribute of a direct link to class D (in general, the list of backlinks is the same as the key to the value: calendar date or ID of the IDO object). And for greater clarity, we change the meaning of the classes: class A is the Product , class D is the Warehouse , class C is the account / invoice (goods movement). Then the semantic load on class B becomes uniquely derived: it is a Product-in-Stock . If replaceThe warehouse is at the Supplier or Buyer , then class B will become the Product-at-Supplier / Buyer .

    The declaration corresponding to the changes made will look like this:


    Any Record upon receipt of specific pointers to the Warehouse and Product objects will automatically receive a pointer to the Product-in-Warehouse object , and if there is none, it will automatically create it. Note: the connection of two classes, Product and Warehouse , through the third class ( Product-in-Warehouse ) is an implementation of the many-to-many relationship , an alternative to the direct exchange of the values ​​of two backlink attributes. Moreover, this option also has the property of uniqueness. In other words, for each pair of objects, the Goods and the Warehouse connecting their objectProduct-in-Stock exists in a single copy. This behavior is due to the uniqueness of the list of backlinks, for which the attribute-pointer to the opposite class is used as the key source. And it doesn’t matter in which of the two classes ( Product or Warehouse ) the uniqueness of the list is declared - the same list of backlinks (with the usual list functionality) in the opposite class will in fact contain a unique set of keys.

    Many-to-many relationship


    A direct many-to-many relationship looks like two interacting backlink lists in each of the linked classes. Such an implementation has generally insignificant practical meaning: only a statement of the fact of the connection of objects, without the possibility to realize through this relationship the consistent interaction of the attributes of these classes. Therefore, in practice, the desired interaction of the attributes is realized through the attributes of the third class, associated with relations with the target classes. In real application models, such constructions are found all the time, and are created in the most arbitrary way, without pretending to be a separate type of relationship.

    It is a completely different matter when a relationship through the third class has the property of uniqueness, like a Goods-in-Stockfrom the example above. Here, the specifics of the third class (communication class) is not so much the use of relationship attributes as sources of a key, but its conceptual “derivativeness” of class relations. Therefore, such a unique (by identifiers) connection of classes through the third class will be further considered as a many-to-many relationship . Such a type can be named as a unique relation , or as a relation-projection .

    Projection relationit is created as a result of the execution of the dialogue, during which the classes connected by the relation are selected, after which the corresponding constructor method creates both the third projection class itself, with the assignment of the corresponding composite name to it, and all other necessary declarations of the relationship attributes and the connectors connecting them. At the same time, any class that forms a relationship with the three classes of projection relations automatically receives a complete set of connectors from the example discussed above, which allows its objects to automatically receive a pointer to the projection object. Pay attention, in order to give greater visual clarity, the ratio of the projected class to the projection class on all schemes looks like a double arrow.


    Remarkably, a combination of projection relationships can implement any multidimensional data analytics. In fact, any projection class can be connected with the projection relation, including the projection classes already available, after which a generalization of numerical values ​​can be organized in the attributes of all projection classes.

    Correspondence


    Increasing the multiplicity of relationships we thus allows the object of one class to address two or more objects of another class, which in turn can also be seen as a logical analogue of the previously discussed communication many-to-many .


    Based on this, it should be assumed that the multiple form of the relationship must have its own projection - a unique form of the multiple relationship, a pointer to the object of which can be obtained automatically.

    And such a unique relationship will really be created if, in the process of creating a relationship-projection dialog, one and the same class are chosen as target classes. And after the relation of a simple class to a projection class is created, the declaration of attributes and connectors will take the following form:

    For all the strangeness of its appearance, it is a logical and fully functional declaration that is practically used, for example, in accounting - to receive objects of mutual correspondence of balance accounts. Strictly speaking, the name borrowed from here - correspondence , which is used below to denote a multiple unique relationship realized by the projection class.

    What should be noted in the above declaration: in contrast to the usual projection, connecting any pair of objects with its only copy, in correspondencesuch a relationship is implemented in two instances, one for each combination of pointers in direct link elements. For these purposes, in all interactions, including the formation of a list of backlinks, reference pointers serving both as values ​​and as keys are supplemented by the index of the element in which they are placed. In addition, to block meaningless double addressing, a reference attribute in the projection class can be assigned a special function that prevents both elements from being assigned the same value.

    Relationship implementation


    There is exactly one way to implement the relationship in the class object - to assign the identifier of the IDO target object to the direct link attribute using the Set method . Moreover, the corresponding call can be initiated both externally and by the data model itself. For example, an attribute can get a pointer to an object from another class through a connector that binds the same reference attributes. Also, a relation can be implemented directly when creating an object, if the Create method is addressed not to the target class, but to the attribute of the relation typed by this class, both the attribute of direct and backward links. In this way, it is convenient to create a new object relative to another object (for example, a new Record regarding the Invoice) An attribute can also receive an IDO by creating the target relationship object with Autoset functionality .

    An external user cannot just take and assign a reference value to an attribute. The sad consequences of opening direct access to the internal identification system are obvious without comment. In addition, outside the space of objects, a separate IDO descriptor, which is called “loses its meaning,” turns into a prime number.

    Therefore, an external user can implement the link only indirectly, in the form of a dialogue, by selecting an element from the list in which each object is represented by its absolute (non-reference) values. The required list is provided to it by the components of the Data-cursors layer (the server part of the interface resources of the object DBMS will be considered later), which then initiate the IDO assignmentaccording to the choice made. The selection dialog can be direct or cascading, which is set based on the existing back connectors. The source for the formation of the dialogue list is the corresponding list of backlinks.

    Functionality Autoset


    This functionality is assigned to the direct link attribute in order to implement the relationship by automatically creating a derived object of the target relationship class. Autoset

    functionality can be triggered by either an inbound connector or an external Update event . In this case, the target relationship object will be created by the functional only if the reference attribute in the source object does not have a stored value.

    Reproduction of the set


    There is a solid rule of logical interaction of values, according to which a value belonging to a particular domain can only be associated with a value whose domain is included in the source or includes the source. In this case, only a value with an equal or more extensive domain can take the initial value. The largest domain (after the Undefined Type ) has an attribute of type Logical , which can take on the value of any other type. Simply put, a connector can bind only the same type of attributes, which was observed in all the examples considered earlier. But here in the next declaration is a passive connector, linking backlink attributes ( A. {B} → C. {D}) is obviously of a different type, explicitly violates this rule, and nevertheless has the full right to life.


    The thing is that in this case the subject of interaction is not the meaning itself, but the quantitative aspect of the associated sets that have taken the form of backlink lists. Let us consider in more detail the logic of what is happening.

    A static attribute, the derived value of which is not initialized, when accessing it with a request, is nevertheless capable of returning the value by forming it from the incoming connections, if any. At the same time, the attribute itself will not create the stored value anyway, since the request does not contain an explicit indication of belonging to the transaction , which means that the database must retain its stateunchanged. It is another matter when the transactional nature of the effect is obvious. In this case, the static attribute that was not initialized earlier can and should, within the framework of the general change in the state of the database, form a stored value. As can be seen from the declaration, the connector in question and its target attribute C. {D} will be triggered when a value is assigned to the attribute C. [A], that is, transactionally. And if the derived value at this moment does not exist, the C. {D} attribute begins its formation according to the original pattern provided by the connector.

    As a value, the list of backlinks is derived from direct links. In other words, attribute C. {D} there is the only way to create your own list the size of the original one is to create the required number of objects of class D and assign each of the created objects a pointer to their own object. Such creation with assignment can be done with one Create command to your own address. That the attribute (and if to be absolutely exact - then the list functionality assigned to the attribute) does - for each element of the source list. And since the value of this element is a reference pointer, the type of which is known, then by analyzing the tuple of the class of the created object, a direct link attribute of the required type is determined, which is assigned the pointer value extracted from the element.

    As a result of all these actions, a similar set of derived objects of the target class, pairwise connected with the model ones, is created according to the existing sample - the set of derived objects of the source class.

    Internal relations


    To link objects of the same type (objects of the same class), a relation is used that is created directly inside the data class. At the same time, the way to implement the relationship itself remains unchanged - two reference attributes are created in the class, connected by reference connectors, and typed by its own class.

    What is noteworthy, the correspondence discussed in the previous paragraph can also be attributed, albeit partially, to internal relations, since it connects objects derived from one class. The truth does this through third-party objects.

    In contrast to the usual relations created by the visual dialogue, during which the connected classes are sequentially selected, internal relations are created by the example of attributes in the visual space of the target class.

    Through an internal relationship, an attribute can create a connector on itself. This is a very effective technique, allowing to implement various kinds of generalizations of meanings, including generalization by “cumulative total”.

    The functional meaning of the internal relationship is determined by its type.

    Chain relationship


    The internal one-to-one relationship allows one to form sequential chains of class objects, which is why it is called chain .

    You can implement a chain relationship in various ways: either by taking the connector to the previous object from the list of backlinks from the common owner, or using the Autoset functionality that implements the relationship by creating a subsequent object relative to the previous one. In the latter case, it is convenient to use the Update event method to initiate the functional .

    Examples of use are the passage of a part of a processing cycle organized as a sequence of operations, or settlement periods of a year: quarterly or monthly, with cumulative totals at the beginning and end of the period. If the power of the chain ratio is increased to three, the objects of the class can form a logical similarity to a three-dimensional crystal lattice. This design can be used for a wide variety of modeling behavior, including in physical environments.

    Recursive attitude


    The internal many-to-one relationship , called recursive , allows you to create tree-shaped data structures of variable nesting depth formed by objects (object hierarchies a la folders in the file system). A typical example of the use of recursion is the calendar schedule of work at the construction site, in which, together with the recursive one, the chain relation is also used. The most convenient and natural way to implement a recursive relation is to create a class object relative to an already existing parent object.

    In relation to the tree hierarchy of objects formed by a recursive relation, when implementing the multiple relations of these objects with objects of other classes, there are two logically obvious restrictive rules.

    Rules for interacting with recursion


    Graphically, the rules for the interaction of third-party classes with a recursive one can be illustrated as follows:

    1. In the case of a multiple relation with an object hierarchy, an object of a third-party class can implement its direct link only to an object that belongs to the lowest level of this hierarchy, that is, to an object with an empty value for the backlink attribute of a recursive relation.

    2. Only an object belonging to the highest level of the object hierarchy (having an uninitialized value of the attribute of a direct recursion link ) can implement its direct link to an object of a third-party class.

    It is worth noting that these restrictions apply only to the implementation of multiple relations of a class that has an internal recursive relation with other classes, and do not apply to similar unitary relations. These rules, characteristic of hierarchies in general, are not strict, but are advisory in nature. Compliance with these rules at the level of the object model is not controlled in any way, and is entirely vested in the interface part of the application.

    Recursive projection


    If one or both classes connected by a unique projection relation also possess internal recursion , then it is logical to assume that derived objects of these classes should be interconnected by projection objects not only at the lowest level of the object hierarchy, but also at all subsequent levels . Approximately as shown in the following figure:


    To implement such a relationship, the projection class must also have a declaration of a recursive relation.

    Accordingly, when a recursive relation is created in the projection class , then, in addition to the two reference attributes and connectors of this relationship, the model constructor creates two more additional attributes, as well as a set of connectors, which provide the projection to the next level of the object hierarchy by the value of additional attributes :


    The constructor assigns additional attributes (marked with [*] in the diagram) to the same type as the attributes of the direct link of the projection to the classes being connected, thereby translating them into the category of relationship attributes. But there is a difference: there is no backlink for additional attributes.

    Additional attributes get their stored value (pointer to an object) from the recursion direct link attributes of the same type, through active connectors marked in the diagram with the symbol (=). If both values ​​are received, then the communication scheme with number 2 will be implemented. If recursion in one of the objects connected by the projection is not implemented (communication schemes with numbers 1 and 3), then the corresponding additional attribute will not have a stored value, but when it is accessed, it will return pointer to an object without recursion. This behavior is typical for static attributes, and was mentioned earlier: when the Get method accesses an attribute whose value is not initialized, it is nevertheless capable of generating a return value by polling incoming connectors. In the diagram, the corresponding passive connectors created by the model constructor,

    It is worth mentioning that a completely similar set of additional attributes and connectors will be created by the model constructor when the internal recursive relation is declared in such a projection variant as the Correspondence considered above .

    Structural interface


    The need for a structural interface arises whenever it is required through relationships to obtain unified access to various entities. In other words, entities with a different set of details must be reduced to a homogeneous set (from the point of view of details). Well, at least then, to present them as a general list.

    The first solution to this problem is provided by the mechanism of class inheritance : a descendant class inherits a tuple of attributes of the ancestor class. This is quite enough, for example, to bring all the wealth of types of financial documents into one list of the type Date , Number , Document Name / Operation , Amount .

    This solution can be arbitrarily called the interface " from above ." It works well, but unfortunately not all entities share a common ancestor. A specific example is given to us by the specifics of accounting in construction: several Customers finance large Construction projects , which consist of several Construction Objects , the Works for which are structured according to the types of work , and are included in various Agreements (with the Customer ). It takes the progress of the work (financing, expenses incurred, man-hours, ...) to bring together the overall picture a la Gantt chart. Multiple inheritance is not a good idea. Moreover, the effect of multiple inheritance can be obtained by combining heterogeneous entities with a one-to-one relationship - which, apparently, is the philosophical meaning of the unitary relationship. For our example, the result is achieved by combining a unitary relation and recursion , and in declarations it looks like this:

    Each of the above-mentioned subjects of "construction" accounting automatically (using Autoset ) creates a paired object in the Gantt class, after which it passes a pointer to its logical " owner " into this object (as the value of the attribute of a direct recursion link), as well as its other values . The pointer to the “ owner ” is transmitted through auxiliary attributes, the same as in the recursive projection scheme, on which they are indicated by the symbol [*]. Both the creation of Gantt objects and the transfer of values ​​to their attributes is carried out through a unitary relation, logically connecting the “two parts as a whole. ”

    Such a solution can (conditionally) be called thesideinterface"(Experts in the terminology we will correct), since there is another way of uniform representation of entities, which is very suitable name - Interface " below "His idea is that as the value stored in the attribute a unified data structure at the right value. Interface type , which transmit the values and requiring a unified view. So in particular "work" accounting " wiring " that are exactly the same look relatively insensitive, despite the fact that p zmescheny in different classes of documents and often not in a single copy.

    It is probably worth noting that the existence of such different options for partial structural unification suggests that there is no universal interface solution in nature.

    Interface type


    In the object data model, any structural type most naturally exists as a user class, whose identifier ( IDC ) is a handle to this data type. Accordingly, an interface data structure can be defined as a class, and its use as an attribute value should be considered as a kind of modification of a unitary relation , in which the attribute of a direct link to an interface class does not store the interface class object identifier (IDO), but the object itself. Since the object being “included” as a value loses its independence, together with it it ceases to have its own descriptor. Now its identifier is a composite value in terms of the IDO of the owner object+ IDA of the attribute in which it is placed. This solution allows you not to worry about how to create an included object and implement a relationship with it - all this happens automatically when you create an owner object during the initialization of its attributes.

    Since it is initially assumed that the “interface” object will be included in the composition of objects of various classes, the traditional way of ensuring the symmetry of a relationship by creating a reference attribute in each of the linked classes ceases to be optimal. In fact, with this method, a certain number of reference attributes will be declared in the tuple of the “interface” class, of which, when the relationship is actually implemented, there will always be only one value. Therefore, another option was chosen, asymmetric in the declaration, but nevertheless preserving referential symmetry during implementation.

    In the interface class, the role of the backlink attribute for all created interface relations is performed by the same attribute - Own, to which, so that it can accept the value of any reference type, the User Defined Type is forcibly assigned . As a matter of fact, the assignment of this type to the Own attribute plays the role of a flag marking the class as " interface ".
    The resulting declarations of the “ interface ” relation (on the right), in comparison with the declarations of the usual unitary relation (on the left), look like this:

    The logic of determining the interface type also establishes the order of its use: the class declared as interface forms an independent data type (structural type), which complements the standard set of types involved in the formation of the menu for selecting the attribute typing dialog. When choosing this type and assigning it to an attribute, the model constructor will create all the declarations shown in the diagram.

    Service classes


    In fact, utility classes are ordinary data classes that are used by the data management system to solve its internal utility tasks. The difference between service classes and others is only that they are created by the control system automatically when a new database is generated, and accordingly they have fixed descriptors that are a priori known to the system.

    Super class


    The set of data objects symmetrically connected by reciprocal links is a closed system within which natural inter-object navigation is not limited by anything. But since, for reasons of reliability and security, direct access to objects is prohibited, there is a problem of entering such a system. Using this utility class , called the Superclass , and its derived Super Object , with fixed values ​​of IDC and IDO descriptors, helps to overcome it .

    When the designer creates an application for each new custom class, a multiple relationship with the Super-class is automatically created for this class . Thus, the previously mentioned setservice attributes of the class ( Type , Own and Del ) is supplemented by the fourth member - the attribute of direct reference to the Super-class. The superclass, in turn, gets the backlink attribute typed by the IDC of the newly created class. Thus, upon the creation of custom classes, the Super-class becomes a kind of owner of their entire set, which allows the Super-class with its fixed descriptor to be used as an entry point into the current data model. Notably, an attribute identifier ( IDA) The backreference in the Superclass strangely coincides in value with its class identifier ( IDC ).

    In the process of creating a class of a derived object ( Create ), it automatically initializes its service attributes, including the attribute of a direct link to the Super-class , which receives the fixed IDO of the Super-object . At the same time, as a result, the pointer to the new object replenishes itself with the corresponding list of backlinks of the Super object . Thus, solely upon compliance with the standard rules for the implementation of relations, the Super-Objectbecomes the owner of lists of objects of each class, in other words, a complete set of objects. This circumstance allows us to use the Super-object as a natural entry point into the database , which provides access to lists of class objects.

    Let's pay attention to an important point - a data class, like a declaration, does not have a physical pointer to a list of its own objects. There can be no other relationship between data and metadata except a logical one.

    And one more detail: when organizing the dialog for selecting an object, the default Data cursor , unless otherwise specified, uses a list of backlinks of the target class from the Super object .

    Class global


    Any application needs global values ​​permanently accessible to all parts of the application. To declare such values, the Global service class is used , in the derived object of which they are stored. The specificity of the Global class is the fact that it is associated with the Superclass not by a multiple relation , like all other classes, but by a unitary one-to-one relation . In other words, relative to the Super- object, the Global object exists in a single copy, and since its position in the tuple of the Super-object is known, access to its values ​​is carried out in one step.

    Depending on the features of their use, the entire set of global values ​​can be conditionally divided into groups. The first group includes isolated values ​​that are used on their own, usually in interface forms, such as the name of the organization (own). To access such values, a route is enough: Super-classGlobalAttribute .

    The second group is formed by the so-called borrowed values, such as the VAT rate . In order to use the borrowed value, the class must have a relationship with the Global class , and obviously - multiple. If such a relationship is declared, then the model constructor in addition to it creates a connector that allows the created object to automatically receive a pointer to the Global object .

    In addition to absolute values, reference values can also be global . Such values ​​are most often used as default values ​​specified during application setup, for example, links to Currency objects that form a Ruble-Dollar pair. Since the relationship of the type many (Global) to one (Currency) will strain common sense, global reference values ​​create a slightly different way: first, an Undefined Type attribute is created, in atomic (for a single reference) or enumerated (for multiple links) form, and then its type is redefined to User Defined Type = IDCtarget class. In other words, a direct link attribute is created without declaring the relationship itself. This technique is used wherever there is no practical sense in declaring a relationship, and an attribute of the required type is necessary (as, for example, when implementing the recursive projection discussed above ).

    In addition, all values ​​stored by the Global object are divided into general and user . General, such as the name of the organization or the VAT rate , are the same for all users of the database. Unlike the Reporting Period or the default Warehouse pointer(for a particular storekeeper, for example), which should be individual for each user. To create and store user values, objects of the User class are used .

    User class


    The main purpose of the User class is that it is used to build an authentication system for the end users of the database. If during authorization the user name and password entered by the user coincide with the values ​​of the corresponding attributes in one of the User objects , then authorization is considered successful, after which the values ​​of all other attributes of this object become available to this user (and only him) as global values.

    It is implemented as follows. The Global and User classes are related by a multiple relationship . When creating a new static attribute in the User class , in the Global classa pair of the same type and the same name dynamic attribute ( user-defined ) is automatically created , which after creation receives a passive incoming connector from a pair-specific attribute in User . When accessing the user attribute in Global , this attribute makes an attempt to get its value through the connector, and at this moment, the runtime instead of the list of backlinks to User objects substitutes a pointer to the only such object obtained during user authorization.

    Note that an attribute can get its value through a connector through a list of backlinks from multiple sources or by converting these values ​​to a single one (for example, by summing), or if there is a condition (context) that allows one to distinguish the unique one from the set of values. In the absence of an appropriate condition or transformation (functional), the attribute is prohibited from creating an inbound connector through the backlink attribute. For a user attribute in the Global class, this limitation is overcome artificially.

    Local databases


    Somewhat earlier in the text, it was already mentioned that many objects connected by relations form a closed system, the only entry point to which is the Super-object . Within one physical database, there may be an arbitrary set of such closed systems. Each such system can be considered as a logical database, completely isolated from other similar logical bases. Each logical base has its own entry point, its own Super-object . In other words, to generate a new logical base, it is necessary to create another object derived from the Super-class .

    This problem is solved with the help of three utility classes: UserGlobal : Super-class, and the Global class will be the leader in this bunch . It is the Global class that is associated with the logical database, and each derived object of this class in the corresponding attribute stores, including the user name of “its” base. The presence of a one-to-one relationship allows you to automatically create and associate a new Super-object with it when creating a Global object . Regarding the Global object (considered as an instance of a logical local base ), objects of the User class are created(named Users of this instance of the local database). After passing the authorization procedure, for this User, descriptors ( IDOs ) of not only the Users object , but also the Global and Super- objects associated with it are stored in his record in the Client Table . It is the user pointer to the Super-object (the root element of the local database) that will be used by the control system as a value that is automatically assigned to the corresponding service attribute of an object of any class when creating this object on the initiative of this particular user.

    What is important to note is that all mutually isolated logical databases are subject to the rules of the data model that are common to them, which apply to the entire space of the physical database.

    Relationship Inheritance


    When it is created, the heir class receives the full tuple of attributes of the ancestor class, and together with the attributes of the heir class receives the complete set of relations of the ancestor class in full. And at the same time an interesting detail pops up.

    Each new class, regardless of how it is created, must form its own relationship with the Super-class in order to have a complete list of its objects in an explicit form. But the successor class cannot directly create such a relationship, since it already inherits the attribute of direct reference to the super-class as part of the entire ancestor tuple. In addition, although the ancestor class does not create its own objects, nevertheless, its list of backlinks in the super-object must include a complete list of objects derived from all its child classes. (For example: there are manyDocuments in general, and there is a private set of invoices only .)
    A list of objects for the ancestor class will be formed without any interference with existing declarations, since all of his heirs have received his parental relationship with the super-class. In the case of the successor class, the class constructor implements the partial creation of a new relationship - the existing direct link attribute is used (no new one is created), a link attribute is created for it in the super-class, and both attributes are connected by a link connector .

    Thus, during inheritance, the bilateral symmetry of the relationship with the superclass is partially violated: now two or more (depending on the inheritance depth) backlink pointers in the superclass will correspond to one direct pointer to the superclass. But such an exception to the rule is private in nature and seems logically justified.

    Domain Refinement


    The domain of values ​​of the reference attribute is formed by the identifiers of objects derived from the opposed relationship class and all its successor classes. In applications, there is often a need to forcibly narrow the domain of values ​​of a reference attribute, restricting it to a single class.

    Consider the following example:

    An abstract Counterparty has one of two organizational forms: Legal or Individual (successors of the Counterparty class ). In exchange transactions, the Counterparty plays a certain Role : it can be a Supplier , a Buyer, or both at the same time. Obviously, between the Counterparty and the Role there is a very specific relationship, which we will separately consider a little later. The Invoice class is an abstract exchange transaction in which the natural multiple relationships with the Counterparty are declared andRole . In our example of specific operations of exactly two: The credit and expenditure , the heirs of Surface and its relations.

    The heirs of the Waybill use the relationship with the Counterparty in the form in which it was inherited. Both Incoming and Expenditure invoices implement this relationship by selecting the target from the general list of Counterparties , in which both Legal and Individuals are present .

    The inherited relationship with Role requires redefinition , since the subject of reference forInvoice can only supplier , and for consumables - only buyer . The redefinition of inherited relations ( domain narrowing ) is achieved by replacing the identifier of the ancestor class identifier with the identifier of the inheriting class in the attribute properties, for which the reference attribute provides the model constructor with an appropriate dialog. Note that after clarifying the relationship from the direct link in the incoming and consumables overhead, in the lists of backlinks Supplier and Buyeronly invoice objects corresponding to their role will automatically fall. But symmetric redefinition of the relation also for reference attributes of these classes will be considered good form.

    In the previous example, the Invoice logically connects the Counterparty with its Role . Let's consider this connection in more detail, using the same set of classes, but presented in a slightly different perspective:


    The Counterparty can be both the Supplier and the Buyer . This fact is declared by the creation of two separate unitary relations of the Counterparty with these classes, without creating a common relationship with the Role . At the same time, a common ancestor Role is necessary, since it carries not only a relationship with the Consignment Note , but also an additional set of attributes common to the Supplier and the Buyer , necessary, for example, for organizing various settlements. The logical relationship between the Counterparty and the Role is as follows (using the example of the Supplier -Incoming invoice ): The Counterparty acquires the status of a Supplier (forms an object of the Supplier class and implements a relationship with this object) if there is at least one Incoming invoice . In order for this connection to receive a physical implementation and work as an internal rule of the data model, you should use the Autoset functionality , as shown in the figure:


    The left side of the figure shows that the presence of a unitary relationship between the Counterparty and the Supplier allows the Incoming invoice to potentially get a value for any of its direct link attributes when assigning a pointer to another direct link attribute. But since the Supplier is logically secondary with us, the Autoset functionality is assigned to the attribute of a direct link to the Supplier . For this purpose, an additional bi-directional back - type connector will be automatically created . If these declarations are available, during execution, after selecting the Contractor object in the delivery note , one of two things will happen. If the Counterpartya pointer Supplier relevant, the connector will transmit it to the appropriate attribute Surface . Otherwise, the back- connector initializes the Autoset functionality , obliging the link attribute that owns it to unconditionally implement the relationship, in this case, by creating an object of the target class. After the Supplier object is created and the pointer to it is assigned to the direct link attribute, the same back- connector will reverse this pointer to the Counterparty object .

    Another example on the refinement of the relationship is presented in the following figure:


    Objects of type Record are always created in the context of the Invoice object with the Create event addressed to its Record backlink attribute . Accordingly, in order to create an object of the desired class, it is strictly necessary to clarify the target class of the backward link. Overriding a class in direct link attribute properties in child classes A record is recommended but not required.

    Selective value transfer


    The value of the S attribute from class B is distributed by three connectors: one common to the S attribute of the ancestor class A , and two private ones to the attributes D and K of its descendants A1 and A2 . Depending on whether the pointer to the object of which of the heirs, A1 or A2 , is received by object B , in the addressed object only one of the two attributes, D or K , will receive its value. Attribute S will get its value anyway.


    This behavior is ensured by the selective properties of the connector ref context , namely, due to the presence of the IDC target class of the connector in the ref socket declarations . The external connector will execute its transfer function only if the ref context provides it with the IDO of the target. And this will happen only when the value of the reference attribute - the IDO of the object is included in the domain of values ​​of the type declared in the properties of the ref socket. Well, it just begs the association with the if statement , which checks the type matching before performing the action.



    Summary


    The symmetric form of realization of communication of objects, based on the mutual exchange of identifiers, is able to automatically maintain referential integrity and logical consistency by the controls of the database itself. In addition, connection symmetry makes possible natural (no Select ) navigation in the multidimensional space of data objects.

    As a matter of fact, the ways to integrate the business logic of the application directly into the logical structure of the database, discussed in this, as well as in the previous publication, can significantly increase the speed of creating applications. Agree, visual design is much simpler than writing and debugging program codes.

    Also popular now: