Мы создали систему магазинов с symfony2, используя доктрину, которая должна генерировать уникальные серийные номера заказов.
Есть объект Order, который изначально имел свойство orderNumber
Сущность Order является нашей «торговой сессией», поэтому сохраняются не только отправленные заказы, но каждый раз, когда пользователь вводит sth. в свою тележку. OrderNumber по умолчанию null и должен быть установлен только тогда, когда пользователь отправляет заказ.
В простом MySQL я бы сделал что-нибудь. как это:
INSERT INTO orders (orderNumber, [...])
SELECT MAX(orderNumber) + 1, [...] FROM orders;
Но чтобы добиться этого в доктрине, мне нужно было бы сделать блокировку записи в таблицу, выбрать максимальный порядковый номер, установить его в порядке сущностей, сохранить и затем разблокировать таблицу. Я не хотел этого делать (причина блокировки таблицы), поэтому быстрым обходным путем было выбить свойство orderNumber и просто показать id в качестве номера заказа.
Но это не очень хорошее решение, номера заказов имеют пропуски и становятся все выше и выше (через 4 месяца мы имеем значение автоинкремента 140 Кб, а номер заказа не должен иметь более 6 символов, поэтому нам нужно решение, прежде чем приступить к этому предел).
Создание сопоставленного суперкласса и разделение сущности Order на отдельные сущности и таблицы для временных и отправленных заказов приведет к слишком большим изменениям кода.
Поэтому следующая идея — создать отдельную сущность OrderNumber с полем автоинкремента и просто установить для нее сущность Order, когда пользователь отправляет заказ. Это, кажется, способ сделать это без особых изменений.
Но, может быть, есть лучший способ решить эту проблему, что является лучшим решением для доктрины?
Это считается недостатком электронной коммерции, когда для номеров заказов используется автоинкремент. Причина в том, что ваши конкуренты могут легко отслеживать эти цифры и более или менее знать, сколько заказов вы получили за определенный период времени. Они могут использовать эти знания в своих интересах. Именно поэтому в нашей компании возник запрос на генерацию случайных номеров заказов. Мы сделали это путем «скремблирования» идентификатора, полученного из автоматического приращения, для создания 6-значного идентификатора, содержащего цифры и буквы (когда вы используете буквы, вы можете легко разместить более миллиона заказов на 6 символов, платежные шлюзы должны быть в порядке с буквами). Это было сделано детерминистическим способом, поэтому это число может быть преобразовано обратно в идентификатор (хотя это не является строго обязательным).
Ваше решение с отдельной таблицей для номеров заказов кажется мне вполне подходящим. Вы также можете иметь уникальное ограничение на orderNumber
и сгенерировать случайное число или хэш случайного числа (начальное число должно отражать фактическое время и идентификатор сеанса пользователя, чтобы ограничить вероятность коллизий) и попытаться обновить объект. Если это не удалось, вы попытаетесь восстановить. Затем вы должны установить максимальное количество раз, когда это может закончиться неудачей, чтобы оно не продолжалось бесконечно, если есть другая проблема.
Описал в этой презентации Доктрина ОРМ: хорошие практики и хитрости
Я хочу предложить вам избегать автоматически генерируемых идентификаторов и использовать вместо этого UUID с, например, ramsey / uuid библиотека.
Таким образом, в качестве примера, ваш заказ может быть похож на
......
/**
* @ORM\Id
* @Column(type="string")
* @GeneratedValue(strategy="NONE")
*/
protected $id = null;
......
public function __construct()
{
$this->id = Uuid::uuid4();
}
Так что это доступно, прежде чем вы сохраните его в базе данных.
Лучшее вдохновение в (Великих!) Разговорах о Пиветте
Надеюсь это поможет