A
A
Alexander Pankov2020-06-03 07:10:20
1C-Bitrix
Alexander Pankov, 2020-06-03 07:10:20

How to generate a unique string before saving to the database (D7 bitrix)?

Hello.
Edition start.

Wrote my module and lie in local/modules/my.name/Order/OrderTable.php
This is the described table model with orders.

Those we have a table in which there are fields id, user_id, delivery_id .... in general,
there are many fields of all sorts and one of these fields is called order_num and has a string format.
As you may have guessed, this is the order number and it must be unique (exactly number and not id in the database)

class OrderTable extends Entity\DataManager
{
    public static function getTableName()
    {
        return 'dch_order';
    }


    public static function getMap()
    {
        return array(
            new Entity\IntegerField('ID', array(
                'primary' => true,
                'autocomplete' => true
            )),
            new Entity\StringField('ORDER_NUM', array(
                'required' => false
            )),
.......
    }

The description of the model is something like this (above)
I had the task of assigning a unique order number to
the simplest case - this is to take the last number and add 1 - it turns out a new order number,

I decided this through events and in the same file local/modules/my.name/Order /OrderTable.php added
public static function onBeforeAdd(Entity\Event $event)
{
    $result = new Entity\EventResult;
    $data = $event->getParameter("fields");
    if (!$data['ORDER_NUM']) {
        $resOrders = OrderTable::getList([
            'select' => ['ID', 'DATE_CREATE', 'ORDER_NUM'],
            'order' => ['ORDER_NUM' => "DESC"],
            'filter' => ['!ORDER_NUM' => false],
            'limit' => 1
        ]);
        if ($arOrder = $resOrders->fetch()) {
            $newOrderNum = (int)$arOrder['ORDER_NUM'] + 1;
            $result->modifyFields(['ORDER_NUM' => $newOrderNum]);
        }
    }
    return $result;
}

Those I have somewhere far away in the code there is a function for creating an order, it is generally in a different class, inside which I call
$res = OrderTable:add([...]);
$orderId = res->getId();

When the record in the database is about ready and there are all fields (but without the order number field),
then the onBeforeAdd event fires, which takes and searches in the order table for the order with the last number
, gets it (number) and assigns it +1 - this turns out number for a new order
is already being saved to the database.

The code has been working for a long time, but recently orders with the same numbers began to appear (1-2 times a month), I looked, and their creation date matches up to a second, I suspect that the onBeforeAdd event, when it makes a selection, works with one data set, and when assigns, then already with another, it seems to be called a collision or a violation of data consistency. (those orders are created in 1 second and for us it turns out that onBeforeAdd works 2 times for each order and gets the same last number, maybe it works at the same time)

Help me find a solution that would not create the same order numbers for me (did not save rows with the same field to the database)
Thanks in advance for your help!

Answer the question

In order to leave comments, you need to log in

2 answer(s)
L
Lander, 2020-06-03
@usdglander

searches in the table with the order for the order with the last number
gets it (number) and assigns +1 to it - this is the number for the new order

You are not serious, are you? These things are done differently. An auto-increment is hung on the number field, and when adding, a record is first added, the number assigned to it by the database itself is retrieved, and then all fields are saved.

A
Alexander, 2020-06-03
Madzhugin @Suntechnic

There can be only one case when you need to generate an identifier before entering into the database, and this is when the client is forced to perform operations related to a record not made in the database with an unlinked state.
Example - you create a to-do list on the client and add new items to this new list. And you need it all to work, even while there is no connection to the database, and it will be synchronized later. In this case, UUIDs are invented.
In your case, there is nothing of the kind, so it's correct - an auto-incrementing field.

In the simplest case, +1 in other cases (wholesale order, individual delivery, distant warehouse), order numbers can take the form AA-02-1122, AA-02-1123, AA-02-1124.

And that has nothing to do with the case at all. At all. This number is generated AFTER adding a record from prefixes and ID: {OrderType}{Delivery Type}-{WarehouseNumber}-ID
You can write it in a separate field, which you can name Order Number and be happy.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question