Applied objects


When to use references, queries, selections, and objects

1C:Enterprise 8 provides several methods to obtain data. References, queries, selections, and objects can be used to read data from object entities (i.e., catalogs, documents, etc.). For a detailed description of the differences between a reference, selection, and object, see section Using data types for manipulating database objects. This article contains recommendations on choosing the data access method.

As a rule, a query is the most efficient way of reading data. It explicitly specifies how to select records and what fields should be read. Therefore, when a query is executed, only the data that is required will be selected from a database and transferred to the client computer. If you use queries, you do not have to read fields and tabular sections that are not required in your specific case.

Another advantage of a query is the ability to read all the required data from several interconnected tables at once. Therefore, if you need to read data from several objects or obtain data from other tables connected with the objects, using queries would be more efficient than making several calls to different data. Note that from the performance point of view, the number of database calls is also important, not just the volume of data that is read, since every call adds to the overheads.

However, the query will read data from a database with each call. Therefore, if you call the same data multiple times, it will be read multiple times. You can avoid this by calling reference properties. In this case, object caching is used, and no repeat reading will be performed if object data is called repeatedly within a defined period of time. It should be noted, however, that when any field is called through a reference, the object is read in full (including all fields and all tabular sections). Therefore, a reference can be used for multiple calls if reading the full object cannot significantly slow down the execution. For instance, if you want to obtain the Posted property of a document through a reference, the document will be read in full (including its tabular section). If a tabular section of a document might contain several hundred rows, it is better to use a query.

Of course, if you need to call the same field within the same algorithm multiple times, it is better to read the data, store it in the memory as a variable and call the data already read. However, if you obtain data through a reference, the system may output the data that has already been read earlier, even if it was read in another call from 1C:Enterprise script, since data is cached for the whole client session.

The option of caching presentations is also worth mentioning. If, for example, you need to obtain a presentation of a catalog item, it is better to transform a reference into a string instead of calling the name through a reference. In this case, a special feature will be used to obtain presentations (as with the case with caching), and if the object's presentation is not yet cached, the object will not be read in full: instead, only the fields that are necessary to obtain the presentation will be read.

If you need to obtain a list of objects to display on the screen or send to print, it is better to use the Query object to create a presentation, instead of expecting the presentation to be created automatically when a reference is transformed into a string. For instance, if you output a sales report into a spreadsheet document, it is very easy to hamper performance tremendously if you output references to goods in your document. The report will be correct since the system automatically transforms references into strings. However, if you have several hundred or thousand strings, this can slow down the process of report creation tremendously. In this scenario, we recommended that you obtain presentations directly in the query and include obtained presentations in a spreadsheet document as strings.

A similar case is when you need to display query results in the form by dumping data to a value table or a value tree. If the cells of a table box display columns with references, this can slow down viewing of a value table in multiuser scenarios. This will also negatively impact individual user experience and the operation of the system on the whole. We recommend that you obtain both references and their presentations with the help of a query and have data displayed in a table box in such a way that cell text would be taken from the columns that contain primitive types only.

However, note the following: when a value table is viewed by the user, reference presentations are called as the rows are displayed; and when a query is used to obtain presentations, these will be obtained for all rows at once. At the same time, if you search through a value table, presentations for all rows will be selected (separately), which is a lot less productive than obtaining these presentations with a query.

When information is processed (e.g., when a document is posted), we recommend that you use queries to obtain object fields instead of calling a large number of objects via references. For instance, if you need to obtain a certain attribute for all products of the document's tabular section, it is better to run a query through the tabular section and obtain this attribute for each product, instead of iterating through this tabular section and obtaining an attribute for each product via a reference.

If you use a query, all data that is read is stored in the RAM of the client computer. If you need to process huge volumes of data, it is better to use selections. A selection does not provide the flexibility to filter and order information and it reads all fields and tabular sections of the objects. However, it does read data in portions and can therefore be used to process any volumes of data without storing them in the RAM.

When objects are obtained from a selection, they are not reread. This is why, if you need to perform mass modification of objects, using selections is more efficient than reading references with a query and obtaining objects for each reference.

As far as object search (searching for references to objects) with simple conditions (by code, name, etc.) is concerned, search implementation using queries and object manager methods (FindByCode() and others) do not differ much from the platform point of view. Use managers to perform single search operations. The main advantage of the managers is that they can be written in a module very briefly. Use queries if you need to search with complex conditions or to search for several objects.

Direct deletion of objects without deletion marks and reference integrity check

1C:Enterprise provides a reference integrity check feature to delete objects in two stages: firest, setting a deletion mark, and then deleting the object with reference integrity check. However, this is a service feature and you do not have to use it on a mandatory basis.

References to objects that do not exist are not an error from the platform perspective. For instance, even if you use the reference integrity check feature for database objects, references to deleted objects can be obtained from the saved values of report settings.

You can use 1C:Enterprise script tools to mark an object for deletion or to delete it directly, without a reference integrity check. Therefore, interactive user experience supports both the deletion mark and direct deletion options.

To avoid errors, the standard action called from the list when the Delete key is pressed attaches a deletion mark, while Shift+Delete directly deletes the object.

To prohibit an end user from performing direct deletion, disable the "Interactive delete" right for the corresponding configuration objects. Note that this right, like all others, is enabled by default.

Therefore, the direct deletion option (without a reference integrity check) should be introduced by the developer of the configuration when roles are set and by the administrator when roles are assigned to users. In most cases, it is a good idea to prohibit interactive deletion by users and thus ensure the reference integrity at all times. However, direct deletion can be useful in some cases. For instance, you can enable it for staff members responsible for the initial population of an infobase (before the system is put to operation) or for objects that are not referenced by other configuration objects.

Using the DeletionMark field of a database object

1C:Enterprise database objects contain the DeletionMark field. This field is used when objects are deleted with reference integrity control. This feature helps to avoid deletion of an object by a user if the object is referenced from other data stored in the database.

From the platform point of view, direct deletion, i.e. deletion without a reference integrity control, is possible, and the presense of references to missing objects in a database is not an error. The scope of use of this feature is defined by the developer of the configuration and the administrator. The developer of the configuration can control whether direct deletion of certain types of objects can be called by users with the help of Interactive delete rule. For instance, you can disable direct deletion for all users or enable it for some users. This right influences only interactive actions called with standard system commands. If an object is deleted using 1C:Enterprise script tools, you can have this right checked within the module. Of course, direct deletion is also possible in some scenarios, if this is in line with the logics of the task to be solved. This is the case when data is deleted in bulk with a scheduled data processor. In this case, user rights verification is not performed.

Deletion with reference integrity control is a separate service that, however, does not impact other system features. A deletion mark only shows that the user is going to delete the object. The DeletionMark field in 1C:Enterprise does not differ from other system fields of an object in its behavior. It can be set by assigning an object property value, and the object will be marked for deletion after it is written into the system.

You can also use a SetDeletionMark() method instead of setting a deletion mark by directly assigning a value to the object's property and writing this object. This method sets the property to the value specified in the parameter, writes the object and performs other additional actions depending on the type of object. For instance, a posted document is unposted, while all subordinate items of a catalog and subordinate catalogs in a given catalog are marked for deletion. When a user sets the deletion mark using a UI command, actions included in this method are performed. It should be noted, however, that these actions are only a recommended standard way for setting deletion marks. They are not mandatory. If a deletion mark is set by assigning a property value and writing an object, no additional actions are performed. Therefore, the developer can implement setting a deletion mark without any additional actions if needed.

A deletion mark is a field whose value is used during the deletion with reference integrity control, but setting and removing a deletion mark is not a separate, dedicated process from the object point of view. This is why there is no special handler that would accompany setting and removal of that mark. Just as for any other field of an object, the DeletionMark field value can be analyzed in the BeforeWrite() and OnWrite() handlers to perform certain checks or other actions. If you only need to analyze the value written, it is enough to check the value of the field. If you need to determine whether the changed value was written, you need to read the value of this field from a database and compare the value obtained with the current one in the BeforeWrite() handler.

Note that tabular field extensions contain the BeforeSetDeletionMark events. However, these events accompany only deletion mark calling with the help of a standard command. This is why these events can only be used to handle interactive call of a deletion mark in specific forms. If you need to handle common tasks that include control of this field value or perform any deletion mark-related actions, use the events of the object itself.

If the document is marked for deletion, this document cannot be posted. However, a document marked for deletion can have register records, since the posting concept in 1C:Enterprise is not strictly connected with those records. For instance, this is used for documents intended for manual editing of register records. If such documents are marked for deletion, no register records should be deleted in them, as the user can remove a deletion mark and the records will not be lost. You can use 1C:Enterprise script tools in the configuration to disable the activity of register records when a deletion mark is set for such a document. This would be a methodology approach that combines a deletion mark and disabling of register records activity.

Using the Posted field and the posting process

1C:Enterprise 8 documents support the posting feature, which is implemented at the system methodology level. It reflects business events described in the document in the accounting records of the system. The posting mechanism minimizes the effort required by the developer in standard scenarios and at the same time provides the flexibility to change the standard methodology.

This feature provides a special document attribute showing that it is posted, and there are also posting and unposting processes.

The attribute is the Posted system field. The main purpose of this field is to distinguish documents that are already reflected in the accounting system from the documents that have been saved but should not yet affect any accounting records. These documents are a sort of "drafts". For instance, an operator has not yet entered all the required data but needs to quit the program for some reason. He or she can write the document without posting it and get back to it later. Documents that are posted and not posted are shown in the list of documents with different icons.

Posting and unposting in 1C:Enterprise 8 are particular instances of a document writing scenario. The attribute that shows whether posting or unposting should be applied when writing a document is set in the Write() method call parameters. Therefore, the document can be written in the usual manner, posted, or unposted. If a document is posted, True is set in the Posted field, and the Posting() handler is called in addition to the regular actions performed during writing. If a document is unposted, the UndoPosting() handler is called and the Posted field is set to False.

Using the Posted field and the posting process is just a methodology proposed by the system.

You can change the value in the Posted field without posting or unposting the document. All you have to do is change the field value and write a document. This can result in an unposted document with records. Note that if the Posted field is changed this way, the Posting() and UndoPosting() handlers are not called. These handlers accompany explicitly initiated posting and unposting processes, and not the fact that the Posted field was changed.

Document records can be created outside the document posting. Moreover, they can be created by an object other that the document. To this end, all you have to do is write a set of register records with a filter by this document.

This default methodology is the simplest way to manage a document and its records in the scenario when a document contains information on a certain event that took place at the enterprise, and the records reflect these events in various accounting records. If the RegisterRecordsDeletion property is set to AutoDelete in the document's metadata, the existing records are deleted automatically before posting or during unposting. Therefore, if a standard methodology is used, the developer only needs to implement creation of new records in the Posting() handler.

On the other hand, flexibility of the Posted field and the posting process allows to implement more complex posting scenarios if necessary. For instance, you can create a document in which some records are created in the posting process and some are entered manually by the user.

The Posted field and the posting process only make sense for documents that can be posted (those that have the Post property in the metadata set to Enable). Some documents should never be posted. They have the Post property set to Disable in the metadata. These are, for instance, documents that do not affect accounting records in any way. In addition, documents that are meant for manual entering of records should never be posted either. These documents will have records, but you do not have to divide such documents into posted and unposted ones. This is due to the fact that all information (attributes and records) is entered when the document is entered, without distinguishing between the initial information and that obtained during posting.

Note that documents that should not be posted have an icon similar to that of a posted document in the list of documents. This is because the user should first notice the documents that should be posted but have not been posted yet. It is less important to differentiate documents that do not have to be posted and those that have already been posted.

Using data types for manipulating database objects

The 1C:Enterprise model for the development of applied solutions uses an object-based approach to data manipulation for some entities of a subject area. These entities are described in the configuration with the help of the following metadata objects: Catalog, Document, ChartOfCharacteristicTypes, ChartOfAccounts, and ChartOfCalculationTypes. From the point of view of the 1C:Enterprise data model, a database stores objects for these entities. Of course, the query language provides access to these entities, as well as to any other data, through the model of relational tables. However, access with specialized script objects intended for manipulating such data is provided through an object-based methodology.

Let us review the types used to manipulate these entities in the configuration. We will review the types and their use with the example of a catalog. A structure of similar types is used for the other metadata objects mentioned.

The CatalogsManager type is intended for accessing the managers of specific catalogs. In addition, it provides the AllRefsType() method to obtain the TypeDescription value that contains the reference types of all catalogs in the configuration. For instance, you can use this value (through a ContainsType() method) to check whether the type of a certain value is a reference type of some catalog.

The CatalogManager type provides access to common actions for a specific catalog. Its methods are used to perform activities related to a catalog, not to its specific objects. For instance, its methods can be used to create a new object or to find an object by code. The manager is a certain entry point to a specific catalog within an object model of the 1C:Enterprise script.

Note that the system can contain a single object of the CatalogsManager type and a single object of the CatalogManager type.

Let us now review the types CatalogRef and CatalogObject in more detail. The following figure shows how a catalog is stored in a database.

https://kb.1ci.com/bin/download/OnecInt/KB/1C_Enterprise_Platform/FAQ/Development/WebHome/en_360026820953_.files_ns_shema_1.png

The catalog is stored in a table. Table entries define a database object, i.e., a catalog item. The database object includes an entry in the main catalog table and the entries from all the tabular sections of the catalog that relate to this object. Therefore, the database object is an entry that consists of the main table and tabular section rows.

A Ref field is included in a catalog table to store values that explicitly define objects (catalog items) in the 1C:Enterprise database. If you need to reference a database object in any other table, the field of this table will store the value of the Ref field.

Two major types are used to manipulate the catalog in the script: CatalogRef.???? and CatalogObject.????, where ???? is the metadata name of the catalog. It is important to note that there are distinct types for each catalog that are created in the system when a catalog is created in the metadata. Therefore, the reference types of two different catalogs will be different.

The purposes of types CatalogRef and CatalogObject are notably different. A value of type CatalogRef stores a reference that identifies an object in a database, while a value of type CatalogObject is used to read and write object data.

A value of type CatalogRef is used everywhere a reference to an item should be stored. Actually, the CatalogRef value only stores the internal identifier (the same that is stored in the Ref field of a catalog table). This value is stored in the fields of other database tables, it is selected in the input box and specified in the query parameters when data is searched via reference, and so on. It is important that a value of the type CatalogRef can always be compared with other values of the type CatalogRef and the values are always equal if these are the references to the same database object (regardless of the method used to obtain the value and its source).

A value of type CatalogObject is mostly used to create new objects or to modify or delete the existing ones. Besides, the CatalogObject type is used to display and edit all catalog item data in the form of an item. CatalogObject is also used to edit the rows of the catalog list (CatalogObject is not used to display list rows). You can obtain several objects of type CatalogObject for a single catalog item. These values are only equal if we are talking about the same script object. Two script objects obtained for one catalog item will not be equal, even if they read the same database object, and all object data is the same.

You can use a catalog manager to create an object. In this case, a new object that is not yet included in a database is created. If you write it, a new object appears in the database. You can obtain an object from a reference. In this case, the existing object referenced through a reference is read from the database. You can obtain an object from a selection (CatalogSelection) as well. Object data is then filled with the data read from the selection.

https://kb.1ci.com/bin/download/OnecInt/KB/1C_Enterprise_Platform/FAQ/Development/WebHome/en_360025947114_.files_ns_shema_2.png

CatalogObject optimizes the process of writing changes into a database. For instance, if you have not changed the attributes of the object itself, only minimum information on changes will be written. If you have not changed any rows of a tabular section, the tabular section will not be written. If you only changed or added a few rows, only the ones that were modified or added will be written. However, if you have deleted rows or changed the order of the rows, all the rows of a tabular section will be written.

Optimistic locking is applied to the objects, i.e. the object cannot be written if it was changed in a database after reading. This feature ensures the logical integrity of modified objects. Anyone who modifies an object can be certain that their changes will not rewrite changes introduced by other users (in other sessions), or by other objects of the same session. This locking type does not prevent other sessions or the same session from changing the object. However, the object will not be written if it was changed in the database after reading and before writing.

In addition, there is pessimistic locking mechanism that prohibits changes within this or other sessions before this script object removes the locking. Use the Lock() method to activate this mechanism. In general, it is used to block objects that are being edited in the form. Extension of a catalog item form automatically activates the locking to make sure that the user will be able to write the object once they start editing it.

Both CatalogReference and CatalogObject provide access to the object data (table field values) via properties. Since the purpose and usage of these types differ significantly, these scenarios are implemented differently as well. The CatalogObject value stores properties directly in the script object. When the existing object is being read, its properties are filled with database values, and new object properties are initialized with default values. The CatalogRef value reads data from a database when the properties are accessed. However, to eliminate the need to read data every time properties are accessed, object data is cached. If you access properties of a given database object via references, data is only read when you access the properties for the first time and after the system uncaches the object. Object data is stored in cache for about 20 minutes, but if at least 20 seconds passed and then the object is accessed, the system checks whether the database object was modified and updates the cached data if needed. If the object is written within this session, it is immediately updated in cache. The number of objects that can be stored in cache is limited. Note that the system uses separate caches for each transaction, so when you access object data via references you certainly get up-to-date data.

The CatalogSelection type is used for dynamic iteration through catalog items. The mechanism of object table selection does not differ much from the selections of other tables. Note that the items read in the selection can be obtained as CatalogObject values. In this case, they will not be read from the database again. The selection always reads object data in full (all fields and all tabular sections).

The CatalogList type is used to create a dynamic view of catalog data in the Table box control. You can set up the structure of the fields (columns) that are read, as well as set up filtering and sorting. The list reads data in portions as the user navigates through a table box.

The catalog also defines several extensions of controls and forms that can be used to interactively input and view catalog data. Extensions are not data types. They basically add some specific properties, methods, and events to the corresponding objects. In addition, extensions define any unusual behavior of forms and controls when a user configures the system and interacts with it.

Using types for manipulating non-object data

All entities that are supported by the 1C:Enterprise 8 development model and are stored in a database can be divided into object and nonobject ones. Since these entities differ by nature, manipulating these entities using 1C:Enterprise of script tools also differs greatly. For information on object entities manipulation, see section Using data types for manipulating database objects. This section provides information on manipulating nonobject entities.

Nonobject entities are registers (information register, accumulation register, accounting register, and calculation register), and sequences and recalculations of calculation registers. Constants are also nonobject entities, but they are not reviewed in this section, as the database stores one value for each constant and they are not difficult to handle. We will review nonobject entities on the example of an accumulation register and an information register. Note that an information register is the only register you can use without a recorder, so its usage model is more expansive in comparison with other recorders, and its use with the recorder is mostly similar to other nonobject entities.

Data storage model

From the point of view of the 1C:Enterprise data model, a database stores records for nonobject entities. A record is not a database object. No internal identifier is supported for it. A record can be described in full with the values of its fields. Therefore, if you delete a certain record and then write a new one with exactly the same values of all the fields, you will obtain the same database state from the point of view of the applied solution logics. This is a principal difference between a record and an object as part of object entities, since a database object has an internal identifier, and you cannot create the same object twice.

For instance, if you have an accumulation register that stores the movements of the stock from the goods and warehouses perspective, each record is fully defined fully by the type of goods, a warehouse, and the specified quantity. Indeed, from the point of view of the applied solution logics, such a record describes the movement of a certain quantity of a certain product along a certain warehouse. You can create a second record like this and the two would not differ unless the field values differ. An object that represents a physical person may have some personal characteristics that do not depend on the field values. This person can change the name, last name, and passport data, but the person still remains the same object.

Unique records

An important consequence of the specifics of nonobject entities described above is the inability to write references to these records to the database fields. It should be noted however that there is a unique key for each entity in 1C:Enterprise. This platform uses the unique key to handle various tasks. For instance, you can target a certain record in a table box. For all nonobject entities that have a recorder, the unique key includes a recorder and a line number. A line number is used to ensure that the record is unique and to sort records within the recorder. A combination of dimensions and the period (if the register is periodic) functions like a unique key for information registers that are not subordinate to recorders.

If an information register is subordinate to a recorder, its unique character is also supported by a combination of fields: a recorder, a line number, dimensions, and a period. The first is defined by its subordination to the recorder, while its basic applied logics (storing resource values by a combination of dimensional values and the period) define the second. If you set that the periodicity of the register is defined by the recorder's position in the timeline, the unique dimension key includes a recorder as well to ensure additional period detailing within a second.

Subordination to a recorder

Subordination of records to a recorder is mandatory for all registers, except for information registers. The subordination of records is also mandatory for sequences and recalculations. Records that are subordinate to a certain recorder are called register records.

Subordination of register records to the recorder defines the lifetime of these records from the point of view of the applied logics. The recorder (document) is considered to define whether these records exist or not. As a rule, register records are created by the document with the help of 1C:Enterprise script tools in the process of posting. Records that reference the recorder can be created without a recorder, but these records are still deemed subordinate to the recorder. You cannot write a record without specifying a recorder. If you delete a recorder, its subordinate records are also deleted.

Unlike tabular sections, register records are subordinate to the recorder, but they are not part of it. When a document is read, its subordinate register records are not read, and while it is written, they are not written automatically. However, when a recorder is deleted, its records are deleted too. You can have records automatically deleted when objects are posted or unposted. This service option is set in document properties as part of the configuration. Therefore, register records are not part of an object, but are subordinate to it.

In 1C:Enterprise 8, the availability of register records subordinate to the document (recorder) is not strictly related to the Posted state of the document or to the deletion mark. Documents that have not been posted or have been marked for deletion can also have records. For instance, this is used for documents intended for direct input (manual input) of register records. In this scenario, the user inputs register records directly, so the posting concept makes no sense. If the Posted or DeletionMark field is modified directly (without using the SetDeletionMark() method or the UndoPosting event), register records are not deleted.

Therefore, connections between register records and documents are quite flexible. On the other hand, ensuring the logical integrity of connections between documents and their register records demands some effort on the part of the configuration developer. For instance, it is more complicated to edit document records in the form than to edit tabular sections (which are an integral document part). The simplest register usage is creation of register records at the time of posting. In this case, you only need to ensure that register records are written in the posting handler, and the platform automatically supports other logical connections.

Data types used for manipulating objects in 1C:Enterprise script

The AccumulationRegistersManager type provides access to the managers of specific registers. You can use the AccumulationRegisters global context property to call this type.

The AccumulationRegisterManager type provides access to common actions that relate to a specific accumulation register. You can use its methods to perform actions applicable to the register and not to its specific records. For instance, methods of this manager can be used to create an object for manipulating records (RecordSet), to obtain a register selection, and so on. The manager is a sort of entry point to a specific register in the 1C:Enterprise script object model.

The register manager also provides a set of methods to perform actions related to the main purpose of the register. You can obtain balances and turnovers for an accumulation register or obtain slices of the first or last records of an information register. Note that these methods are handy for performing these actions in simple scenarios only. Similar data can be obtained via virtual query tables. Queries are more flexible. From the system performance point of view, calling queries and calling manager methods do not differ much.

Note that the system can contain a single object of the AccumulationRegistersManager type and a single object of the AccumulationRegisterManager.XXXX type for each register (where XXXX is a register name).

A record set is the main type used for modifying the data of nonobject entities. Type AccumulationRegisterRecordSet should be used to read, modify, and delete register records. A record set always operates a set of records filtered by some criteria. To describe these criteria, use the Filter property of a record set. Registers that are subordinate to the recorder are always filtered by recorder.

In practice, a record set is a collection of records that can be read and written. A record set provides only one method for modifying data: Write(). Unlike the methodology used in manipulating object entities, there is no deletion concept for nonobject entities. A record set can only be written. At the same time, all the existing records that satisfy the current filtering criterion are replaced with the records that are stored in the set. Therefore, to delete a set of records, you need to set the filter and then write the set without adding any records to it.

You can also write a set without replacing its items. This is controlled by the Write() method parameter. Writing without replacing means that new records are added to the database without deleting the existing ones. Note that line numbers are adjusted to ensure sequencial numbering of records within a recorder. Usually, writing without replacing is used when a large volume of register records needs to be written.

You do not have to read a record set to write data (which makes the deffenenbce with similar object operations).

No locking concept can be applied to the data of nonobject entities (we are not talking about transaction locks, of course). Therefore, when a set is written, data that has been modified in another session or another set in this session after reading a record set might be overwritten. Remember this when using record sets for interactive editing.

Information registers that are not subordinate to recorders deserve attention as well. You can use filters with different combinations of dimensions and periods for record sets of information registers that are not subordinate to recorders. The image below shows some possible filters.

https://kb.1ci.com/bin/download/OnecInt/KB/1C_Enterprise_Platform/FAQ/Development/WebHome/en_360026820993_.files_im204.gif

Note that a set can be read and written without filtering data by any fields. In this case, all register records will be read and therefore written. If one makes a mistake in a module (for instance, reading a record set or applying a filter is missing), writing a set can result in the complete clearing of a register, since writing without a filter actually replaces the entire register with the content of a record set.

Records in accumulation register record sets have the AccumulationRegisterRecord type. This type is only used to write data in a record set. This value is never used separately from a set of records.

Besides a record set, the InformationRegisterRecordManager type is also provided for an information register that is not subordinate to the recorder. This type is used to read and write a single register record. First of all, it is used to edit a single record in the form. With this type, you can also read a record with certain key field values, modify the fields (including the key ones), and then write the record.

This is an auxiliary type. It uses two record sets to work with a register (with filters that correspond to the key fields of the record being read and written respectively). Therefore, by implementing handlers in a record set module, you can fully control register data modification, including the scenarios when data is modified with the help of a record manager.

The AccumulationRegistersRecordKey type can be used for unique identification of a register record. For example, it is used to identify rows of a table box that represents a register list. You can activate any row you need. Key properties are defined by the fields that form a unique register key. These are dimensions, a period, and a recorder for information registers (the recorder is only included if periodicity by a recorder's position in the timeline is used). A recorder and a row number are used for other registers. A key for a register record can be created with the help of a manager.

The AccumulationRegisterSelection type can be used for dynamic iteration of register records. A selection feature of non-object tables does not differ much from that of reference tables. Note that a selection always reads record data in full (all fields are read).

The AccumulationRegisterList type can be used to dynamically view register records in the TableBox control. You can set up the structure of the fields (columns) that are read, as well as set up filtering and sorting. The list reads data in portions as the user navigates through a table box.

The register also defines several extensions of controls and forms that can be used to interactively input and view register data. Extensions are not data types, they simply add specific properties, methods, and events to the corresponding objects. In addition, extensions define any unusual behavior of forms and controls when a user configures the system and interacts with it.

An extension for editing a single record in a form is also supported for information registers, together with the extensions that show a list and a record set in the form. In this case, the information register record manager acts as the main form attribute.

Developing a periodic information register structure

One of the most common use cases for periodic information registers is storing the change history of some object-related data. When information registers are designed, the most complicated question is how to reflect data from a certain subject area in the structure of these registers.

1C:Enterprise 8 information register can contain multiple dimensions, resources, and attributes. A common question is how many information registers are needed to store several values that change with time. You can create a single register with several resources to store all values at once, or you can create several registers, each with a single resource that stores a single value.
Each information register is a standalone table. Each entry of a periodic register contains information about the values of certain resources by a certain combination of dimensions within a certain period of time. Each resource value is recorded explicitly and takes effect at the specified time. A register record cannot state that the value is not changed. When a slice of a register (a set of resource values at certain time) is requested, the platform searches for the latest entries by a combination of dimensions and returns the resource values that are found.

There is no uniform rule on how to design registers, i.e., "create one register" or "create many registers". When you design a periodic register, proceed from the assumption that each entry should reflect the fact that the values for all the resources as of a specific moment of time have been set in a database. Note that the register entry will reflect the fact that the user has set values for all the resources regardless of their previous values.

When you design a register, you need to analyze how values actually change with time and develop a model to reflect these value changes in a database. It is very important that the user understands how a subject area is reflected in an information register. This determines whether a register is used correctly.

Let us review a very common example of a register that stores exchange rates. You need to store the exchange rate and conversion factor for each currency. You can create two registers: one for storing the history of exchange rate changes, and another for stroing the history of conversion factor changes. On the other hand, you can create a single register where each entry stores both the exchange rate and conversion factor. Obviously, the conversion factor will change much less often. A single register is easier to implement, and it is more user-friendly. Both options are possible. In the first one setting the exchange rate and setting the conversion factor are treated as separate actions. Of course they can be edited in a single form and written as a single document, but you have to ensure that a user looking at the register lists understands that the change histories are stored separately. In the second possible scenario setting the exchange rate and setting the conversion factor are treated as a single action. When a new exchange rate is set, a new conversion factor value must also be set. Of course you can implement filling the conversion factor with the previous value during the record creation, so that users do not have to enter it every time. It is important to ensure that users who create records or view the record list understand that each entry sets both values and they take effect at the specified moment.

In some scenarios several values are closely connected to each other, and there is no reason to keep separate change histories. For instance, as a general rule, all pieces of passport data (series, number, date of issue, etc.) change at once. The values included in the change history can be united to reduce the number of independently stored histories (as is the case with the exchange rate and conversion factor). We recommend that you unite histories when you need to store a large number of values. It is a good idea to group values based on their meaning. It is also very important to present this grouping visually to the user. For instance, if you create a periodic information register to store the price of an item and a standard discount, the record editing form (or the form used to edit the document that generates the information register records) should state that a new price and a new discount take effect on the specified date.

Note that grouping several values into a single information register makes sense, and not only because it reduces the number of tables and increases performance. In general, it is more convenient to deal with a single action of changing several values than with multiple histories.

Another aspect to consider when you are designing information registers is the ability to introduce new dimensions. For instance, if you store prices of goods in a periodic information register, you can later introduce a new dimension (i.e., a price type) to store several prices with user-defined types. However, you need to keep this option in mind when designing the register structure. In particular, this can be used as a criterion that defines whether several change histories can be grouped into a single register. If introducing new dimensions will require you to divide the register, it makes more sense to create two registers from the beginning. For example, uniting prices and minimum stock reserve in a single register is not the best option.

Since an information register is a single table in a database, it is very easy to evaluate the advantages and disadvantages of different register structures from the performance perspective.

A large number of information registers can impact the performance in scenarios where you need to obtain object data and data from periodic registers related to that object and having a specific time stamp. It is obvious that you can obtain a slice from a single register with a large number of resources a lot faster.

Writing a single record with multiple resources is also faster than writing to several information registers.

If you expect a large number of records that reflect frequent changes of a single resource value, the database grows faster when the register has multiple resources. This can significantly affect the database size, especially if one of the resources is a value storage that stores an image or some binary data. We recommend that you store such data in a separate register.

Using script tools for working with applied objects

Working with applied objects (configuration objects) is similar to working with other objects, as both processes have certain principles in common. By understanding these principles you can quickly learn to manage all applied objects, whether they are catalogs, charts of accounts, documents, registers, or any other applied objects.

This section is a theoretical one, but in order to successfully develop with 1C:Enterprise you need to understand how objects are classified. The following table lists the types of 1C:Enterprise script objects with practical examples, a brief description of each type, their typical properties and methods (those that are common for different objects):

Object typeDescriptionTypical
properties and methods
Manager of applied objects of specific type

Examples:

  • CatalogsManager
  • DocumentsManager
  • ConstantsManager
  • AccumulationRegistersManager
  • ReportsManager
  • DataProcessorsManager

An object of this type provide access to the managers of a specific applied object.

Usually such objects are accessed via global context properties, for example, Catalogs.Employees, Documents.Account, InformationRegisters.CurrencyRates, and so on.

These objects are collections of values that can be used to iterate through their elements using the For Each loop.

Properties correspond to the names of applied objects and are themselves objects of "applied object manager" type.

Applied object manager

Examples:

  • CatalogManager
  • DocumentManager
  • ConstantManager
  • AccumulationRegisterManager
  • ReportManager
  • DataProcessorManager

This is the central object of the object model that you can use to obtain any other objects, such as references, selections, objects to be changed, record sets, and so on (see section "Object interconnection" later in this article).

An object of this type provides access to an applied object as a set of items. Methods of this object can be used to search for data, obtain selections, create new records, or call forms and templates of the applied object.

Typical properties (for catalogs and charts):
  • <name of a predefined item>

Typical methods:

  • Select()
  • FindByCode()
  • FindByAttribute()
  • EmptyRef()
  • CreateItem()
  • CreateRecordSet()
  • GetTemplate()
  • GetForm()
Ref

Examples:

  • CatalogRef
  • DocumentRef
  • ChartOfAccountsRef
  • ChartOfCalculationTypesRef

This object unambiguously identifies a database object (for example, a catalog item or a document) and can be used to access the object in read-only mode. You can use properties and methods of this object for reading the attributes of an item or accessing its tabular sections.

References are stored in the attributes referencing the items of the applied object. For example, the Employee attribute of the Recruitment document stores the reference to the particular item of the Employees catalog.

Note that register records have no references.

To change a database object (such as a catalog item or a document) you have to obtain the object itself using the GetObject() method.

Typical properties:
  • <attribute>
  • <tabular section>
  • DeletionMark
  • Date
  • Predefined
  • Ref

Typical methods:

  • IsEmpty()
  • GetObject()
  • GetForm()
  • Metadata()
  • Copy()
Selection

Examples:

  • CatalogSelection
  • DocumentSelection
  • DocumentJournalSelection
  • AccumulationRegisterSelection

You can use this object to iterate through database objects. For example, you can iterate through catalog items or through documents within a journal.

Note that this object is not a collection of values, so you cannot iterate through its elements using the For Each loop.

The properties are similar to properties of objects of the Ref type.

Typical methods:

  • Next()
  • GetObject()
Object

Examples:

  • CatalogObject
  • DocumentObject
  • ChartOfAccountsObject
  • ReportObject
  • DataProcessorObject

Provides access to an item with the option to write the changes to the  database. This object has methods that can change the item in the database, such as Write and Delete.

This object is basically used for generating reports or running data processors.

If an applied object module (do not confuse it with the form module) has some exported module variables or procedures or functions, these are added to the properties and methods of this very object.

There is no such object for registers. The changes of register data are always done through a set of records (see later in this article).

The properties are similar to properties of objects of the Ref type.

Typical methods:

  • Write()
  • Delete()
  • Lock()
  • Unlock()
  • IsLocked()
  • Copy()
  • GetForm()
  • GetTemplate()
  • Metadata()
List

Examples:

  • CatalogList
  • DocumentList
  • DocumentJournalList
  • ChartOfAccountsList
  • AccumulationRegisterList
  • FilterCriterionList

This object is used to manage a list of items in a table field. It can be used for managing columns, as well as for filtering and sorting list items.

This object cannot be created using 1C:Enterprise script, instead it is created automatically when you add a table field to a form. Of course, you can create a table field in a screen form using 1C:Enteprise script, and then an object of this type is created automatically.

Typical properties:
  • Columns
  • Filter
  • Order

Typical methods:

  • Refresh()
Record set

Examples:

  • InformationRegisterRecordSet
  • AccumulationRegisterRecordSet
  • AccountingRegisterRecordSet
  • CalculationRegisterRecordSet
  • SequenceRecordSet

A record set can be used to handle several records of an applied object (usually, a register) at the same time. You can read an entire record set from a database, then add some new records to it or change the existing ones and then write the record set to a database (in a single transaction).

Documents have Records property, which is a collection. It provides access to record sets of each register selected in the Register records tab. Document register records are usually created via this property when the document is posted.

Typical properties:
  • Filter
  • ThisObject

Typical methods:

  • Add()
  • Delete()
  • Clear()
  • Write()
  • Read()
  • Count()
  • Unload()
  • Load()
Record

Examples:

  • InformationRegisterRecord
  • AccumulationRegisterRecord
  • AccountingRegisterRecord
  • CalculationRegisterRecord

This object provides access to a single record of a record set in order to define its dimensions, resources, and so on. This object is returned by methods of other objects, for example, by the Add method of the AccumulationRegisterRecordSet object.

An object of the Record type is not a constant identifier for a specific register record (unlike the Ref object for catalogs and documents). Information register records have no identifiers that never change in time; each register record is defined unambiguously by the values of its dimensions (including system ones, such as Period, Recorder, and LineNumber).

Typical properties:
  • <dimension>
  • <attribute>
  • <resource>
  • Active
  • Period
  • Recorder
  • LineNumber
  • RecordType

Typical methods:

  • PointInTime()
Record key

Examples:

  • InformationRegisterRecordKey
  • AccumulationRegisterRecordKey
  • AccountingRegisterRecordKey
  • CalculationRegisterRecordKey

This object is required to identify a register record in a table field (for example, in a record set of a recorder document, or in a list of all register records). It is used for positioning at a particular register record of a list of records.

Typical properties (except the information register):
  • LineNumber
  • Recorder

Information register properties:

  • <Dimension name>
  • Period
  • Recorder

Specific objects

Some of the important objects that do not fit into the classification above are:

Object typeMatching 
applied object
Description

Information register record manager

Information registers

This object is used to perform operations on a single record of an information register. Only independent information registers (the ones that are not subordinate to a recorder) can have this object.

Note that even if records are edited using a record manager, a register record set is still used at the lower layer: when records are saved or deleted, the events of the register record set module are triggered.

ChartOfAccountsExtDimensionTypes
ChartOfAccountsExtDimensionTypesRow

Charts of accountsThis object is used for working with a list of external dimension types attached to an account.

AccountingRegisterExtDimensions

Accounting registersThe ExtDimensions property of the AccountingRegisterRecord object is an object of this type. This object is a collection of values and can be used to manage external dimension values for a particular accounting register record.

ConstantsSet

Constants

This object is similar to RecordSet objects in the way that it allows reading/writing values of multiple constants from/to a database in a single transaction. The set of its properties and methods is not similar to that of record sets, and that is why it is put among other specific objects.

ExternalDataProcessorsManager
ExternalDataProcessor

External data processors

External data processors manager is similar to the managers of other applied objects. Its Create(<file name>) method can be used to create an object of ExternalDataProcessor type. This object is in turn similar to the objects of ReportObject and DataProcessorObject types. It provides access to attributes and tabular sections of the external data processor for data processing or for passing report generation parameters.

If an external data processor module (not to be confused with the form module) contains exported module variables or procedures or functions, they are added to the set of properties and methods of the ExternalDataProcessor object.

Object interconnection

Below is a description of interconnections between 1C:Enteprise objects, which are typical for objects with references (catalogs are used as an example).

https://kb.1ci.com/bin/download/OnecInt/KB/1C_Enterprise_Platform/FAQ/Development/WebHome/en_360025947134_.files_objects1.png

NOTE: The diagram does not show all the objects and interconnections possible. For instance, the Copy() method can belong to both the CatalogRef and the CatalogObject objects. In addition, the CatalogManager object has FindByDescription() and FindByAttribute() methods that are similar to the FindByCode() method and return a reference to an item or an empty reference if the item is not found. The diagrams do not also show any specific objects or objects of List type.

And now let us proceed to another interconnection that is common for registers (accumulation registers are used as an example):

https://kb.1ci.com/bin/download/OnecInt/KB/1C_Enterprise_Platform/FAQ/Development/WebHome/en_360025947154_.files_objects2.png

As you can see, the left parts of these diagrams are very much alike, while the right ones are different. You should not think that the RecordKey object is similar to Ref objects, or that RecordSet and Record objects are similar to Object objects, even though there is some resemblance between them.

  • The RecordKey object resembles the Ref object in that it is the most accurate identifier of a specific register record possible (it is not as absolute as the Ref object, though). You should always remember that particular register records have no references, in other words, there are no unique identifiers that would differentiate one record from another and make it unchangeable in time and space.
  • A RecordSet object and a Record object resemble the Object object only by the fact that data in a database is changed via these objects.

Summary

  • Working with any applied object has a great deal in common with working with other applied objects, as it is organized using several 1C:Script objects each of which has its own purpose and a typical set of properties and methods. However, an applied object’s set of properties and methods may vary from the typical one.
  • You can use certain properties and methods to obtain various 1C:Enterprise objects from other 1C:Enterprise objects.
  • Two groups of applied objects can be distinguished: those that contain references (catalog items, catalogs, and documents) and those that do not contain them (usually related to registers).
  • Some 1C:Enterprise objects do not fit into the general pattern and are described separately.

Tips on choosing between a subordinate catalog and a tabular section

1C:Enterprise supports the creation of one or more tabular sections for a catalog. You can use this option to represent data that is related to this item but does not have object nature (if the data has object nature, creating a subordinate catalog is recommended). For instance, you can create the UnitsOfMeasure tabular section for the Goods catalog.

Note that if a tabular section is used, you will not be able to reference the rows of a tabular section, in other words, you will not be able to create an attribute that matches the "tabular section row" entity. For instance, if you create the Education tabular section (instead of a subordinate catalog) for the Employees catalog, you will not be able to select a type like "graduated from" for document attributes. This should be taken into account when you choose between a subordinate catalog and a tabular section.

If you might need to reference subordinate objects in the future (for instance, to create attributes of documents or other catalogs that reference them), it is better to create a subordinate catalog from the very beginning. If a reference to such data makes no sense and can never be a type of a certain attribute, you can create a tabular section.

Below is a list of cases and factors to be taken into account to choose between a subordinate catalog and a tabular section. Study these cases in detail to avoid mistakes when making your choice.

Case 1

You need to store a list of settlement accounts of each contractor in the database. You will most probably have to specify not only the contractor name but also their settlement account in all payment documents. This data is definitely of an object nature and can be identified as a "settlement account".Solution: a Contractors catalog and a subordinate catalog SettlementAccounts with fields Bank, Number, and Account.

Case 2

You need to store a list of units of measure for each product in the Goods catalog and to specify a conversion factor for recalculating each unit into the basic unit of measure. This data is collected from the UnitsOfMeasure catalog that stores all available units of measure. Each row of that subordinate list has no object nature of its own, it is only needed to recalculate from a certain unit of measure into the basic one.Solution: a Goods catalog and a UnitsOfMeasure tabular section with fields UnitOfMeasure and ConversionFactor.

Case 3

The default user rights feature is not enough for working with specific applications. A system that would allow different users to approve documents is often needed. In this case, you need to store a list of documents that a certain user (employee) can approve, and that is what the DocumentsForApproval tabular section of the Employees catalog can be used for. This data is not object-based, it simply connects a document and an employee, so you will probably never have to create references to it.Solution: an Employees catalog and a DocumentsForApproval tabular section with the Document field and Is approved check box. Note that this task can also be solved with the help of information registers.

Case 4

You need to store employee family data in the Employees catalog, which includes family members and their relationships with the employee (husband, wife, son, daughter, and so on). As a rule, this data can be represented as a list fully subordinate to the Employees catalog item, and one may consider creating a tabular section. However, if we think about it again, this data definitely has object nature and can be identified as a "family member". In some applications you may need to create references to the employee family members. A similar situation is observed with employee education and previous job experience.Solution: the choice between a subordinate catalog and a tabular section depends on the purpose of your configuration. If you need to create references to certain data in the future, you may want to create the following subordinate catalogs: FamilyMembers, Education, and JobExperience.

Important! Remember that when you call a catalog item, it is read from a database into memory in full, together with all the tabular sections. If a tabular section contains a large number of rows, this may hamper system performance.

Therefore, a tabular section should be used if you do not have to store references to items and the number of items is limited.

Predefined data: troubleshooting

While working with predefined data, you can come across the following issues:

  • An attempt to access a predefined item leads to the following error: "The predefined item is not found in the infobase data". Possible reasons:
    • It is a subordinate node and predefined data items available in the central node have not yet been loaded.
    • The infobase data was initialized when predefined data update was disabled for the entire infobase or for a specific metadata object.
    • Predefined data was deleted.
    • The value of PredefinedDataName attribute of predefined data was cleared.
  • Duplicate predefined data items are detected (two or more data records have the same value of PredefinedDataName property). Possible reasons:
    • Predefined data items were created with DataExchange.Load set to True. For example, this can occur in scenarios featuring distributed infobases.

Troubleshooting

It is recommended that you enable recording events of "Information" level to the event log at all times.

Predefined data items are not found

Filter the event log by metadata object whose data is missing and by the following event types:

  • Data:
    • Modify predefined data
    • Delete predefined data
    • Set predefined data initialization
  • Infobase:
    • Predefined data update
    • Set predefined data update

Events in the list can show why the predefined item is not found.

If the log contains an event of Data.Modify predefined data type, which has an empty string as a predefined data name, it means that a user or 1C:Enterprise script fragment cleared the predefined data name, making the item not predefined. To restore the item, return the previous value to the PredefinedDataName property. It is recommended that you correct your configuration in order to prevent this situation in the future (for example, change access rights or modify the script fragment).

If the log contains an event of Data.Delete predefined data type,  it means that predefined data was deleted by a user or from 1C:Enterprise script. To correct this, create the missing predefined item. It is recommended that you correct your configuration in order to avoid deletion of predefined data that is used in the application algorithms.

If the log contains an event of Data.Set predefined data initialization type where a predefined data initialization flag is set, it means that setting the flag was attempted from 1C:Enterprise script but some (or all) of the predefined items were not created. It is recommended that you correct your configuration (ensure that either all of the predefined data items are created or the missing items are never accessed).

If the log contains an event of Infobase.Predefined data update type that includes the comment "Predefined data update disabled", it means that the predefined data update is disabled at infobase, node, or metadata object level. In this scenario the platform does not perform the restructuring of predefined data. To identify the source of the issue:

  • Ensure that it is not a subordinate node. In a subordinate node, predefined data is loaded from the central node. This is why your application logic should provide the option to load the changes from the central node before the first attempt to access predefined data.
  • Analize the events of Infobase.Set predefined data update type where predefined data update is disabled. If predefined data update was disabled before the configuration update, enable the automatic update of predefined data using the SetInfoBasePredefinedDataUpdate method (if it was disabled for the entire infobase) or the SetPredefinedDataUpdate method (if it was disabled for a specific metadata object). It is recommended that you correct your configuration in order to prevent this situation in the future. Create the missing predefined data items or remove the script that accesses the missing items.
  • Validate the configuration. Probably the metadata object property PredefinedDataUpdate is set to DontAutoUpdate. If this is the case, correct this error.

Duplicate predefined data items.

Duplicates can appear only in data load mode (DataExchange.Load set to True). In this scenario the platform does not check whether predefined data items are unique.

If the event log contains records of Data.Add predefined data type with duplicate PredefinedDataName values, it means that predefined data duplicates are created from 1C:Enterprise script, for example, they were loaded during data exchange.

If the event log contains records of Data.Modify predefined data type with duplicate PredefinedDataName values, it means that duplicates of predefined data are created by a user or from 1C:Enterprise script, for example, they were loaded during data exchange or the load mode specified in the item form is incorrect and the user was able ro specify a duplicate name.

To correct the issue, first decide which item is the correct one (for example, by checking the references to predefined data items), and then make the other item regular (not predefined) by clearing the PredefinedDataName field. Before deleting the item, check whether a replacement of references to this item with the references to the correct item is required.

Guidelines for working with predefined data

If you do not plan to manage predefined data from 1C:Enterprise script and you assume that it is always in the database, do the following:

  • Restrict access to predefined data, so that no one can delete or clear the PredefinedDataName property.
  • Avoid predefined data modification in privileged mode.
  • Avoid modification of predefined data in the data load mode (when the DataExchange.Load property is set to True).
  • Do not disable automatic predefined data update.

Remember that the platform does not create predefined data items in subordinate nodes. Instead, they come from the central node. Thus, when you develop applications that run as distributed infobases, pay attention to the predefined data update at the first start of the application and ensure that the application does not attempt to access the predefined data when it is not yet loaded from the central node.

Autonumbering

This article covers the details of how autonumbering works on the example of a catalog.

Autonumbering overview

Automatic numbering of catalog items provides unique codes for new items. New items are assigned incrementing numerical codes.

The code generation rules are based on the code series settings specified for the catalog.

  • In the entire catalog. All codes in the catalog are unique.
  • Within subordination area. Items having the same parent have different codes, while items having different parents can have identical codes.
  • Within owner subordination area. Items having the same owner have different codes, while items having different owners can have identical codes.

The autonumbering issues new codes in compliance with catalog code series settings.

Let us tackle an example of a hierarchical catalog with item hierarchy, code series = within subordination area, autonumbering enabled.

Let us add the first item to the catalog:

https://kb.1ci.com/bin/download/OnecInt/KB/1C_Enterprise_Platform/FAQ/Development/WebHome/en_360026821013_i8102745_i800081.png

You can see in the figure that automatic numbering of catalog items starts from 000000001.

Let us add the second item to the catalog:

https://kb.1ci.com/bin/download/OnecInt/KB/1C_Enterprise_Platform/FAQ/Development/WebHome/en_360025947174_i8102745_i800082.png

Let us add one more item that is subordinate to the second item:

https://kb.1ci.com/bin/download/OnecInt/KB/1C_Enterprise_Platform/FAQ/Development/WebHome/en_360026821033_i8102745_i800083.png

You can see in the figure that the series code setting affects the new item code generation: the code for the third item is unique only among the items that are subordinate to the second item.

One of the peculiarities of autonumbering is using the leading zeros. This increases the efficiency of search and sorting by code or by number. To search for items or sort items, the platform uses the database index for the code or number field. In order to use database indexing, 1C:Enterprise adds leading zeroes to any new codes or numbers generated automatically.

Leading zeroes are necessary for proper sorting of documents and other objects that have numbers. For example, without leading zeros a document with number "Doc3" goes after a document with number "Doc11", which is incorrect.

Operations with code prefixes

Adding a prefix to an item code being generated only makes sense if the code is a string.

In order to add a prefix to a new code or number, you can use the On set new code event handler. This event is fired when the code generation begins (for example, when the generation of a catalog item code begins). The handler declaration has the following syntax:

OnSetNewCode (<Standard processing>,<Prefix>),

where:

  • <Standard processing> is a flag that shows whether the standard processing is used. If you set this parameter to False in the body of the handler procedure, the standard code generation is canceled.
  • <Prefix> is a prefix that will be used for code generation.

Let us tackle an example of a distributed infobase configuration where prefixes ensure the uniqueness of codes in each node. The following script fragment generates unique codes:

// OnSetNewCode event handler
// Changes the code prefix to the unique prefix defined in this infobase
//
Procedure OnSetNewCode (StandardProcessing, Prefix)

    Prefix=GetNumberPrefix();

EndProcedure // OnSetNewCode (StandardProcessing, Prefix)

where GetNumberPrefix is an exported common module function, which returns the value of some constant. Each node provides a unique value of this constant:

// Returns a prefix for a new number
//
// Return value:
// String - prefix for a new number
//
Function GetNumberPrefix() Export

    Return Constants.NumberPrefix.Get();

EndFunction // GetNumberPrefix()

Instead of the On set new code handler, you can use the SetNewCode() method of catalog object. You can pass a prefix as a parameter of this method, in this case the method finds the maximum numeric part among the codes that have this prefix and generates a code with the numeric part incremented by 1. If you omit the prefix, the method finds the maximum numeric part among all codes available in the infobase and generates a code with the same prefix and the numeric part incremented by 1.

Note that for catalogs that have codes of Number type, the prefix returned by the On set new code event handler is ignored.

Autonumbering support by other metadata objects

Apart from catalogs, the following metadata objects support autonumbering:

  • Document
  • Chart of characteristic types
  • Business process
  • Task

To set numbers for documents, business processes, and tasks, use the On set new number event handler.

To set codes for charts of characteristic types, use the On set new code event handler.

Autonumbering for collaboration

The basic principles of autonumbering are described in Autonumbering. This article describes the peculiarities of autonumbering during simultaneous work of several users.

Let us tackle this issue on the example of catalog (autonumbering is implemented in the same way for other object types).

The autonumbering algorithm is mainly based on the object data stored in a database table. To generate a code, 1C:Enterprise searches the catalog for the maximum code with the specified prefix. As indexing is always supported for "Code" field, the search runs quite fast.

Note that it only searches the existing records. If an object that had the maximum code was deleted, 1C:Enterprise provides this code upon the next request. However, if any object that did not have the maximum code was deleted, or some codes were skipped, 1C:Enterprise never provides the missing codes for new objects. If you want 1C:Enterprise to provide the missing codes, do not use the autonumbering feature. Instead, implement a custom numbering algorithm.

Note that codes are not generated during object creation. Some object creation scenarios actually do not include entering new data. For example, an object can be replicated from another infobase or from an external data source, and in both cases it comes with a code. Consequently, the code generation in such scenarios is just a waste of time because the generated code is immediately overwritten. This is why you need to assign a code explicitly using the SetNewCode() method. However, when an application user opens a new item form, the form extension automatically generates an item code. This is just a service operation supported by the form extension, it is similar to calling the SetNewCode() method in the form opening handler.

Thus, an application developer must call the method that sets a code exactly when it is necessary. Otherwise this would create an unnecessary database call, which might result in unwanted locks. We also recommend that you pay attention to choosing the optimal place for the SetNewCode() call. Calling this method in a transaction can lead to unwanted locks.

To ensure correct numbering in multiuser applications, 1C:Enterprise locks each new code from the moment when it is issued till the moment when an object is written (or when the CatalogObject value is removed from the memory).

Example:

//Fragment 1
Object1 = Catalogs.Products.CreateItem();
Object1.SetNewCode();
Message(Object1.Code);  //4753
Object2 = Catalogs.Products.CreateItem();
Object2.SetNewCode();
Message(Object2.Code);  //4754

//Fragment 2
Object1 = Catalogs.Products.CreateItem();
Object1.SetNewCode();
Message(Object1.Code);  //4753
Object1 = Undefined;
Object2 = Catalogs.Products.CreateItem();
Object2.SetNewCode();
Message(Object2.Code);  //4753

//Fragment 3
Object1 = Catalogs.Products.CreateItem();
Object1.SetNewCode();
Message(Object1.Code); //4753
Object1.Write();
Object2 = Catalogs.Products.CreateItem();
Object2.SetNewCode();
Message(Object2.Code);  //4754

In the first script fragment, the autonumbering issues a code to an object stored in the memory and locks this code. When it issues a code to the second object, it skips the locked code.

In the second script fragment, the same code is issued to both objects because the first object is no longer available when the code is issued to the second object. Note that this behavior is defined by setting Objects autonumbering mode configuration property to Release automatically. If this property is not set to Release automatically, the autonumbering does not reuse the first code, it sets code 4754 for Object2.

In the third code, autonumbering issues a different code to the second object because the first object is already written.

In general, the autonumbering searches for the maximum code, generates the next code based on this one, and checks whether this code is locked. If it is locked, it generates the next code and checks whether it is locked. It repeats this step until it finds a free code. Then it sets this code to a new item and locks it.

It is clear that this algorithm is mainly aimed at code generation for interactive data input. If a user starts entering an item in a form and then another user starts entering another item, 1C:Enterprise assigns different codes to these items.

If a catalog uses autonumbering and its code is blank, 1C:Enterprise generates a code when the catalog item is being written. Thus, there is no need to call SetNewcode() method when an item is created from 1C:Enterprise script. However, you might want to use this method to exclude the code generation from the transaction that writes an item.

Using chart of characteristic types to implement storage of values related to infobase objects

While designing metadata, you may need to decide between adding attributes and using an additional data storage based on a chart of characteristic types.

Let us assume that you need to add some data that describes warehouse properties to a warehouse catalog. For example, you need to store warehouse address for adding it to way-bills handed to forwarding agents. Surely you can do it by adding Address attribute to the warehouse catalog. On the other hand, you can implement an additional data storage as an information register or a catalog tabular section using a chart of characteristic types.

These two options are clearly very different, both in implementation details and in potential use of the resulting solutions.

Adding an attribute is the straightest way possible. This is the closest match to relational data storage model, it ensures optimal usage of stored data and satisfies the majority of usability requirements. Using an attribute does not require any developer efforts. 1C:Enterprise "knows" how to work with the attribute. It provides support for editing the attribute in forms, displaying it in lists, and accessing it from reports. The platform guarantees the efficiency of operations with the attribute, including search by the attribute. However, if you add the attribute, you have to update all of the forms and reports where you want it displayed. If you add another attribute later, you will need to update the forms and reports again.

If you use a chart of characteristic types instead, you can give users the option to add more types of data that describes warehouses. However, this method requires more developer efforts. In this scenario additional warehouse data is stored in an information register or a tabular section. This does not exactly match the relational data model. Actually, instead of implementing additional fields, you use a table. One of the table fields stores values, while another one stores the data type (for example, Warehouse address or Warehouse size). As 1C:Enterprise cannot automatically determine that this data is related to warehouses, you have to implement operations with this data. This also applies to object input forms, list forms, and any reports based on this data. For example, you might need to describe relations between tables in order to create a report with a filter by a characteristic. The main advantage of this method is the option to add characteristics dynamically, without changing the configuration.

It is hard to decide which method is better. We recommend that you first consider adding an attribute. Use a chart of characteristic types only when you have a reason for this. The main arguments for this option are:

  1. Users need to add characteristics without changing the configuration.
  2. The set of characteristics may vary depending on the object instance.

The first argument is mostly related to standard solutions that are deployed in many companies and often require industry-specific customizations. For example, product characteristics often depend on product type.

The second argument is relevant when different object instances can have different properties (for example, if a company sells products of different types).

Considering the implementation complexity of the method that involves a chart of characteristic types, we recommend that you set a limit for the total number of its uses in your application. Use this method only when it is necessary to reach the balance between taking advantage of 1C:Enterprise capabilities and reducing solution support costs.

Document sequences

Overview

The document sequence mechanism ensures that interrelated documents are posted in the correct order. The main idea of this mechanism is that a document posting procedure can depend on certain data stored in the infobase. To be exact, the document posting procedure depends on the data values that were stored in the infobase at the time when the document was registered in the infobase. If this data is changed after document posting, the document must be reposted in order to update its register records. For example, if a document reads item prices from an information register, a price change invalidates the register records of this document and the document must be reposted to correct them.

This mechanism uses the following algoritm. When a document is written, it is registered in a document sequence. It means that the document posting procedure is based on certain data stored in the infobase, and the result of document posting depends on the data values that were stored at certain time. At the end of document posting 1C:Enterprise checks all of the sequences where the document is registered. For each sequence, 1C:Enteprise checks whether all of the documents registered in the sequence before this document were posted in the correct order. If they were posted in the correct order, the document posting is considered to be correct. If they were not posted in the correct order, the document posting is considered to be incorrect and the document must be reposted.

When the data that affects document posting changes, 1C:Enteprise defines which document sequences depend on this data. All of the documents that are registered in these sequences after the data being changed was written get the "repost pending" flag.

Application users can learn which documents were posted correctly and which were not. They can get this data as the point in time, before which all documents are posted in the right sequence. All of the documents posted after this point in time are considered to be posted in an incorrect order. Knowing this, a user can decide to restore the correct order of document posting. This includes reposting all of the documents that belong to the sequence and were posted earlier.

Implementation details

When developing an application, a developer describes which documents are included in a sequence and which data affects their posting. All this data is defined in Sequence metadata object. A developer specifies a list of documents that form a sequence and a list of registers whose data affects document posting. Note that the platform monitors the changes of data that affect document sequences only in accumulation, calculation, accounting, and information registers.

A document sequence can have dimensions. You can use dimensions to split document sequences into smaller parts. For example, if a document posting procedure involves item prices stored in an information register, changing a single item price initiates the reposting of all documents of that kind, even those that do not include that specific item. To solve the problem, you can add the Item dimension to a document sequence. When a document is registered in a document sequence, its registration record includes the items affected by the document. When 1C:Enteprise restores a document sequence, it can determine which items were changed and, consequently, which documents are to be reposted.

Document registration in a sequence can be performed automatically. First, a developer must set a mapping between document attributes and document sequence dimensions. If one or several attributes of a tabular section are included in the mapping, a document is registered in a sequence multiple times, one for each unique combination of attribute values. If attributes of different tabular sections are mapped to sequence dimensions, the number of registrations is the number of unique combinations of these tabular section attribute values. If all tabular sections have unique combinations of attribute values in all the lines, the number of registrations is N1*N2...*Ni, where Ni is the number of lines in a tabular section.

To automatically track data changes broken down by document sequence dimensions, specify a mapping between register dimensions and attributes and document sequence dimensions. Note that documents are not automatically registered in sequences upon creating a document sequence or adding a document type. To register documents in a sequence, you have to write them or write a data processor that registers documents in a sequence.

The document sequence mechanism uses two entities: document registration in a sequence and sequence boundary. 1C:Enterprise сreates a data table for each entity. A registration table stores the details of document registration in a sequence. Both tables can be accessed using 1C:Enterprise query language.

A registration table has the following fields: period, recorder, and sequence dimensions. A document registration table contains records with dimension value combinations that are unique for a single recorder. In other words, a registration table stores a single record for a specific combination of dimension values within a single recorder, still it can store multiple records with the same set of attribute values for different recorders. You can access the table data through the record set that describes document registrations in a sequence. A document object has a collection of record sets that describe its registration in document sequences. 1C:Enterprise uses the record sets from this collection to register documents in sequences when the documents are being written. Note that when the posting is cleared, the registration in document sequences is not cleared. However, an unposted document does not participate in sequence restoration. In all other respects, operations with records sets that describe document registrations in sequences are similar to operations with any other register record sets.

A sequence boundary indicates a point in time (boundary) after which the documents are posted incorrectly. The boundary table structure is similar to the registration table structure, still its content and meaning are different. In contrast to registration tables, boundary tables contain only records that have unique dimension value sets. In other words, there is only one record for a specific combination of dimension values. A period and a recorder specify the point in time of a boundary by specific dimensions. The content of a sequence boundary table may be changed only through a document sequence manager object.

Document writing procedure:

Start a transaction

    Fill the record sets that describe document registration in a sequence

    Call predefined procedure BeforeWrite()

    Write the document

    Call predefined procedure OnWrite()

    Write document record sets that are changed but not yet recorded

        Check and move sequence boundaries to the point in time of these record sets (this action is performed in a record set, not in a document)

    Write record sets describing document registration in a sequence that are changed but not yet recorded

End a transaction

Document writing procedure with posting

Start a transaction

    Fill the record sets that describe document registration in a sequence

    Call predefined procedure BeforeWrite()

    Write the document

    Call predefined procedure OnWrite()

    Call predefined procedure Posting()

    Write document record sets that are changed but not yet recorded

        Check and move sequence boundaries to the point in time of these record sets (this action is performed in a record set, not in a document)

    Write record sets describing document registration in a sequence that are changed but not yet recorded

    Check and move sequence boundaries to the point in time of these record sets

End a transaction

Document writing procedure with posting cleared

Start a transaction

    Fill the record sets that describe document registration in a sequence

    Call predefined procedure BeforeWrite()

    Call predefined procedure UndoPosting()

    Delete record sets

        Check and move sequence boundaries to the point in time of these record sets (this action is performed in a record set, not in a document)

    Write a document

    Call predefined procedure OnWrite()

    Write record sets describing document registration in a sequence that are changed but not yet recorded

End a transaction

Note that the backward movement of a sequence boundary (boundary displacement) can only occur when register record sets are being written with boundaries that are greater (later) than the time of the record set. The forward movement of a sequence boundary (boundary restoration) can only occur when a document is being posted with boundaries that are less (earlier) than the document time, and only if there are no other documents belonging to that sequence between the sequence boundary and the document being posted (so that no documents need to be reposted). To sum it up, automatic boundary displacement can only occur when register data is changed, regardless of the origin of the record set that changes the data (it might or might not be generated by the document). A sequence is restored automatically only during document posting. Writing a document, registering a document in a sequence, or posting a document cannot displace a sequence boundary. Only a register change can displace a boundary.

Application developers can use 1C:Enterprise script methods to set boundaries to arbitrary points in time. They also can get current sequence boundaries, check whether a sequence boundary is displaced, check whether a document belongs to a sequence, and restore sequences.

 

Icon/Social/001 Icon/Social/006 Icon/Social/005 Icon/Social/004 Icon/Social/002