23.01.2017, 13:27 | #1 |
Участник
|
Поговорим о Unit Of Work?
наткнулся на
https://www.youtube.com/watch?v=cm64vkwzxl4 SMART TALKS: Dynamics AX мероприятие что думаете о реализации класса UnitOfWork в Аксапте? что думаете о реализации UnitOfWork по сравнению с InventSumDelta? в комментариях к видео я написал: паттерн Unit of Work: https://martinfowler.com/eaaCatalog/unitOfWork.html полностью паттерн реализован в .net Entity Framework. в аксапте достаточно ограниченная реализация. основное преимущество не в многопоточной вставке, конечно. основное преимущество в комбинации методов обновления и ЧТЕНИЯ (getByKey) особенно когда записи обновляются несколько раз. пример - inventTrans.costAdjustment обновляется каждый раз, когда происходит вставка в InventSettlement. по идее нужно делать inventTrans.update в базе каждый раз. кроме того, есть InventSum, который нужно обновлять каждый раз как только изменяется/добавляется запись в InventTrans. с Unit of work можно сделать алгоритм, который: 1. читает inventTrans из базы один раз. 2. обновляет в памяти 3. читает обновленную версию из памяти 4. в самом конце делает команду обновления в базу. таким образом, сильно сокращается число обращений к базе. за счет этого и происходит оптимизация. главная особенность: getByKey читает запись из памяти, а если записи в памяти нет, то метод самостоятельно читает из базы. за счет этого и достигается унификация алгоритма и щастье программиста. особенности:
ну, и конечно Unit of Work в своем изначальном виде во внеаксаптовском мире часто используется как data source для unit test'ов. Последний раз редактировалось mazzy; 23.01.2017 в 13:42. |
|
23.01.2017, 15:41 | #2 |
Moderator
|
Касательно InventSumDelta и закрытия склада - там не все так просто. Там запросы на обновление написаны достаточно хитро, с тем чтобы предотвратить дидлоки. Сначала все записи, подлежащие обновлению, блокируются, а потом чохом обновляются. Встроенный механизм про блокировки, планы исполнения, дидлоки и тд и тп ничего не знает (и вряд ли его особо удастся обучить этому делу). С учетом этого - я сомневаюсь что этот механизм применим для обновления inventSum или закрытия склада. Для того чтобы этот шаблон был работоспособным, он должен на уровне SQL Server поддерживаться, а не на уровне сервера приложений. Кроме того - не очень понятно что делать в многопользовательской среде. Например - если у нас на лету кто-то другой запись удалил, что с UnitOfWork делать ?
|
|
23.01.2017, 15:48 | #3 |
Участник
|
про удаление:
вне транзакции - это "выстрелить себе в колено" про планы запросов и deadlock: "ограниченная" в смысле интеллекта. тупенький алгоритм, в общем )))) поэтому и спрашиваю. |
|
23.01.2017, 15:52 | #4 |
Moderator
|
Вероятно - ты хочешь сказать "В рамках транзакции и с пессимистическими блокировками". Потому что если мы дофига всего насчитаем в памяти, а потом в момент записи выяснится что работали мы на неактуальных данных, то ведь придется все перезапускать и пересчитывать...
То есть - по большому счету - этот паттерн применим к данным, у которых малая степень конкуренции. Например - заказах на продажу. Все-таки шансы что несколько сейлов вдруг продают один и тот же заказ - пренебрежимо мала... P.S. Хотя с другой стороны - если ты хочешь кэширование, то явно ситуация несовместима с многопользовательским доступом и блокировками. Так что может это все и полезно - но для довольно ограниченного набора ситуаций... Последний раз редактировалось fed; 23.01.2017 в 16:11. |
|
|
За это сообщение автора поблагодарили: mazzy (5). |
23.01.2017, 16:53 | #5 |
Banned
|
Кажется этой ссылки еще не было:
https://blogs.msdn.microsoft.com/sav...series-part-5/ Цитата:
Although the number of insert calls remain 20k, the time fall down from 5 seconds to 1.5 seconds. Now we are more than 3 times faster than the naïve approach that calls the insert statement 20k times through a loop.
Цитата:
X++: public static server void insertWithUnitOfWork() { FooChild child; FooParent parent; // Instantiating the UnitOfWork. // Notice that this method runs on server UnitofWork unitOfWork = new unitOfWork(); int i; for (i = 0; i < 10000; ++i) { parent.ParentId = int2str(i); parent.Name = 'Any name for parent' + int2str(i); parent.Description = 'Any description for parent' + int2str(i); child.ChildId = int2str(i); child.Name = 'Any name for child' + int2str(i); child.Description = 'Any description for child' + int2str(i); // You will just be able to call this method if there is a relation // called FooParent at FooChild table child.FooParent(parent); // Marking these buffers to be inserted by UnitOfWork // The buffers are not being inserted at the database right now. unitOfWork.insertonSaveChanges(parent); unitOfWork.insertonSaveChanges(child); } // Finally, asking UnitOfWork to insert the records at the database. unitOfWork.saveChanges(); } |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
23.01.2017, 17:19 | #6 |
Moderator
|
Еще как-то я не уверен в многопоточной вставке. В документации ничего об этом не говорится. Кроме того - для просто быстрой множественной вставки система вполне может использовать Array Binding. Просто одному оператору insert передается сразу много строк для вставки, без всякого паралелизма..
|
|
23.01.2017, 18:04 | #7 |
Участник
|
Цитата:
Алгоритм может решить послать новый запрос в SQL и, тем самым, запросить выборку заново. тогда выборка из базы и выборка из unitOfWork - две большие разницы. Так, например, складская проводка может быть расспличена или полностью споставлена. Тогда следующая итерация закрытия должна получить новый набор записей. Или, например, сопоставление по клиенту/поставщику. Там query().reset() происходит практически после каждого чиха. |
|
|
За это сообщение автора поблагодарили: ax_mct (2). |
23.01.2017, 18:20 | #8 |
Участник
|
по теоретической части двух центов не имею, но могу поделиться практическим опытом.
успешно воспользовался unit of work при импорте из экселя новых цен поставщиков, когда нужно было сначала создать "заголовочные" записи для основной цены как бы виртуально, а потом к ним "привязать" несколько десятков подчинённых строк с вариациями цен для цвета, размера и проч. обычный импорт тянулся неимоверно долго, после применения unit of work всё стало загружаться в секунды.
__________________
Felix nihil admirari |
|
|
За это сообщение автора поблагодарили: mazzy (2), ax_mct (2), gl00mie (2). |
23.01.2017, 19:50 | #9 |
Участник
|
|
|
23.01.2017, 19:55 | #10 |
Участник
|
ну, есть разница между прогнать N раз цикл по "заголовкам" и M раз по "строчкам" или дробить "строчки" на N циклов, сохраняя каждый раз "заголовок"
__________________
Felix nihil admirari |
|
23.01.2017, 21:48 | #11 |
Участник
|
Из личного опыта:
Не получилось запусть doUpdate() . Может это и фишка конечно. Не получилось достать уже добавленные данные (getByKey() не работал, хотя выше пишут что работает. Наверно я что-то не так делал). Различные проблемы с update conflict. Например запихнуть 2 записи и если update() первой записи обновит вторую, UnitOfWork вылетит. По-моему были проблемы если 2 раза одну и ту же запись добавить. Данные из первого буфера в базу уходили, но надо проверить. Кстате, а пример с добавлением 10к записей пробовали запускать в транзакции? Вроде уже и не такая большая разница |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
24.01.2017, 10:39 | #12 |
Moderator
|
В общем - по итогам чтения дискуссии, у меня появилось впечатление что UnitOfWork в Аксапта - это просто расширенная и слегка недоведенная версия RecordInsertList, а вовсе даже не реализация классического паттерна.
|
|
24.01.2017, 10:54 | #13 |
Участник
|
Цитата:
1. поддерживает несколько таблиц 2. умеет читать недоведенная - да. прежде всего в аксаптовской части. и будешь смеяться - именно реализация классического паттерна. остальные реализации не сильно лучше. просто этот паттерн мало предназначен для серверной части приложения. этот паттерн отлично работает на клиентской стороне (если ему не надо взаимодействовать с другими библиотеками доступа к данным). |
|
24.01.2017, 13:41 | #14 |
Участник
|
Я бы добавил в особенности что нельзя использовать при работе с несколькими компаниями.
|
|
|
За это сообщение автора поблагодарили: mazzy (2). |
Теги |
unitofwork, полезное |
|
|