tag:blogger.com,1999:blog-1453949493029009080.post4160428542652933779..comments2022-02-13T09:42:52.129+02:00Comments on То, что важно лично для меня: Мартин Фаулер. Предметно-ориентированные языки программированияNameRechttp://www.blogger.com/profile/00070033877714975718noreply@blogger.comBlogger13125tag:blogger.com,1999:blog-1453949493029009080.post-23137357221598132812014-05-01T19:31:27.290+03:002014-05-01T19:31:27.290+03:00Сильно смахивает на попытку реализовать сишарпный ...Сильно смахивает на попытку реализовать сишарпный LINQ, только без поддержки анонимных типов со стороны компилятора/IDE.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-1453949493029009080.post-39727589734037190882014-04-29T01:20:20.041+03:002014-04-29T01:20:20.041+03:00спасибо за ссылку, почитал с интересомспасибо за ссылку, почитал с интересомНиколай Зверевhttps://www.blogger.com/profile/08965247674233981930noreply@blogger.comtag:blogger.com,1999:blog-1453949493029009080.post-77340765938689489102014-04-26T01:54:16.691+03:002014-04-26T01:54:16.691+03:00«а вообще, наши ораклисты внушили мне мысль, что т...«а вообще, наши ораклисты внушили мне мысль, что триггеры сами по себе есть зло, и стоит их пименять либо для отладки, либо как временное решение (читай "костыль") при исправлении ошибок, но не как часть бизнес-логики.»<br />-- Все "ораклисты" думают одинаково :-)<br />Есть замечательная статья "Где наша бизнес-логика, сынок?" http://habrahabr.ru/post/65432/ - возможно, она будет "в тему"...NameRechttps://www.blogger.com/profile/00070033877714975718noreply@blogger.comtag:blogger.com,1999:blog-1453949493029009080.post-4426311071259785132014-04-26T01:52:10.079+03:002014-04-26T01:52:10.079+03:00«на что-то такое, что бы сказало генратору SQL, мо...«на что-то такое, что бы сказало генратору SQL, мол в это поле подставь значение из другой таблицы без выборки его на клиент.»<br />-- Почему-то мне кажется, что так не получится. Потому, что значение поля с именем nmStatusMaster должно быть определено *до* выполнения contact_data.Post (за это отвечает ForcePostData(contact_data)). Здесь принципиально, что операция изменения данных должна быть инициирована средствами DataSet.<br /><br />«(а то что у вас эмуляция триггера - это понятно. ещё интересно было бы посмтореть на случаи, когда триггеров больше одного, как тригеры у вас регистрируются и т.п. просто ради любопытства)»<br />-- Пример другого триггера я привёл выше, регистрируются они так:<br />procedure RegisterTriggers(AConnection: TCustomConnection);<br />var<br /> iObj: ITriggerContainer;<br />begin<br /> if Supports(AConnection, ITriggerContainer, iObj) then<br /> begin<br /> iObj.RegisterTableTrigger(snLC_CONT, ProcToEventHandler(hnd_LC_CONT_ApplyTriggers));<br /> iObj.RegisterTableTrigger(snCON_TIME, ProcToEventHandler(hnd_CON_TIME_ApplyTriggers));<br /> end;<br />end;NameRechttps://www.blogger.com/profile/00070033877714975718noreply@blogger.comtag:blogger.com,1999:blog-1453949493029009080.post-47578449115034015142014-04-26T01:44:05.693+03:002014-04-26T01:44:05.693+03:00а вообще, наши ораклисты внушили мне мысль, что ...а вообще, наши ораклисты внушили мне мысль, что триггеры сами по себе есть зло, и стоит их пименять либо для отладки, либо как временное решение (читай "костыль") при исправлении ошибок, но не как часть бизнес-логики.<br />и я с ними начинаю соглашаться и смотреть на базы уже по другому.Николай Зверевhttps://www.blogger.com/profile/08965247674233981930noreply@blogger.comtag:blogger.com,1999:blog-1453949493029009080.post-45898670292595462322014-04-26T01:40:05.819+03:002014-04-26T01:40:05.819+03:00Забавно... :-)
Только что посмотрел - на LC_CONT е...Забавно... :-)<br />Только что посмотрел - на LC_CONT есть триггер уровня приложения.<br />Вот его код:<br />procedure hnd_LC_CONT_ApplyTriggers(P: Pointer; var Event: TComEvent);<br />var<br /> DBC: TCustomConnection;<br /> vOldStatus: Variant;<br /> tabHIS_STAT: TDataSet;<br /> trs: IDBTransaction;<br />begin<br /> with TEvent_TriggerContainer_ApplyTriggers(Event.Parms^) do<br /> if Operation = DC_MODIFY then<br /> begin<br /> { если статус изменился сохранить историю }<br /> with DataSet.FieldByName(nmStatusCode) do<br /> begin<br /> vOldStatus := OldValue;<br /> if Value = vOldStatus then<br /> Exit;<br /> end;<br /> { добавить историю }<br /> if vOldStatus <> 0 then<br /> begin<br /> DBC := ExtractConnection(DataSet);<br /> trs := Transaction(DBC);<br /> try<br /> tabHIS_STAT := OpenTable(DBC, snHIS_STAT);<br /> try<br /> tabHIS_STAT.Insert;<br /> tabHIS_STAT.FieldValues[nmContactCode] := DataSet.FieldValues[nmContactCode];<br /> tabHIS_STAT.FieldValues[nmStatusCode] := vOldStatus;<br /> tabHIS_STAT.FieldValues[nmStatusDate] := DataSet.FieldByName(nmStatusDate).OldValue;<br /> tabHIS_STAT.FieldValues[nmStatusTime] := DataSet.FieldByName(nmStatusTime).OldValue;<br /> tabHIS_STAT.FieldValues[nmStatusMaster] := DataSet.FieldByName(nmStatusMaster).OldValue;<br /> tabHIS_STAT.Post;<br /> finally<br /> tabHIS_STAT.Free;<br /> end;<br /> PassEvent(Event);<br /> trs.Commit;<br /> except<br /> trs.RollBack;<br /> raise;<br /> end;<br /> end;<br /> end;<br />end;NameRechttps://www.blogger.com/profile/00070033877714975718noreply@blogger.comtag:blogger.com,1999:blog-1453949493029009080.post-15890877446883767722014-04-26T01:38:07.961+03:002014-04-26T01:38:07.961+03:00не-не-не. вы не так поняли.
я имел ввиду не написа...не-не-не. вы не так поняли.<br />я имел ввиду не написание апдейта целиком, а замену строки<br />contact_data.FieldValues[nmStatusMaster] := CreateDataSetSelector<br /> .UseDBC(DBC)<br />… .<br />на что-то такое, что бы сказало генратору SQL, мол в это поле подставь значение из другой таблицы без выборки его на клиент.<br /><br />(а то что у вас эмуляция триггера - это понятно. ещё интересно было бы посмтореть на случаи, когда триггеров больше одного, как тригеры у вас регистрируются и т.п. просто ради любопытства)Николай Зверевhttps://www.blogger.com/profile/08965247674233981930noreply@blogger.comtag:blogger.com,1999:blog-1453949493029009080.post-84923530117506617702014-04-26T01:24:17.347+03:002014-04-26T01:24:17.347+03:00«Хотя на самом деле, для ускорения (и чтобы не дел...«Хотя на самом деле, для ускорения (и чтобы не делать лишний round-trip) можно написать на SQL так: <br />update lc_cont set statuscode = :statuscode, … , statusmaster =(select mastercode from users… )»<br />-- Такой UPDATE посредством SQLObjects (представленная к рассмотрению техника) записать очень легко.<br />Но мы стараемся не злоупотреблять инструкцией SQL UPDATE в случае, если к этому нет прямых показаний, по ряду причин.<br />Самая простая состоит в том, что UPDATE нарушает инкапсуляцию таблицы, в которую вносятся изменения - используется знание правил, как там изменять данные. Например, корректировка записи в LC_CONT может представлять собой транзакцию, в которую могут быть включены другие таблицы.<br />Конечно, можно разместить соответствующую бизнес-логику на уровне триггера СУБД для модификации записей в LC_CONT, но это сразу же сделает эту бизнес-логику СУБД-зависимой, а выигрыш в производительности на атомарных операциях будет незаметным.<br />С другой стороны, использование DataSet.Edit и Post позволит разместить бизнес-логику в приложении (либо толстом клиенте, либо на сервере приложений) и сохранить независимость от СУБД, поскольку при выполнении Post будут активированы триггеры уровня приложения. Примером такого триггера является обработчик hnd_CON_TIME_ApplyTriggers, пример которого приводится.<br />Этот обработчик будет вызван при Post в наборе данных, открытом для таблицы CON_TIME (как следует из его имени).NameRechttps://www.blogger.com/profile/00070033877714975718noreply@blogger.comtag:blogger.com,1999:blog-1453949493029009080.post-46337588642608653582014-04-26T00:59:55.092+03:002014-04-26T00:59:55.092+03:00про код из реального приложения - там где вы делае...про код из реального приложения - там где вы делаете<br />contact_data.Edit<br />и ниже определяете параметр StatusMaster<br />как я понимаю происходит выборка этого значения из БД на клиент.<br />Хотя на самом деле, для ускорения (и чтобы не делать лишний round-trip) можно написать на SQL так:<br />update lc_cont set statuscode = :statuscode, … , statusmaster =(select mastercode from users… )<br />ну т.е. вам есть куда ещё развиватьсяНиколай Зверевhttps://www.blogger.com/profile/08965247674233981930noreply@blogger.comtag:blogger.com,1999:blog-1453949493029009080.post-75335957429506444042014-04-26T00:47:58.539+03:002014-04-26T00:47:58.539+03:00ну про отладку я спросил потому, что точку остано...ну про отладку я спросил потому, что точку останова нельзя пставить в середине выражения. например на строке<br />.Open<br />(ну допустим я хочу посмотреть текст генерируемого sql-выражения)<br />хотя понятно, что это не такая уж и проблемаНиколай Зверевhttps://www.blogger.com/profile/08965247674233981930noreply@blogger.comtag:blogger.com,1999:blog-1453949493029009080.post-91717833137339940642014-04-26T00:21:30.547+03:002014-04-26T00:21:30.547+03:00«вот расскажите пожалуйста, как вы ходите отладчик...«вот расскажите пожалуйста, как вы ходите отладчиком по этим текучим интерфейсам?»<br />-- Да как... Обычно... F7, F8, Toggle breakpoint... :-)<br />Но вообще-то, нечасто там приходится отладчиком ходить. Методы довольно простые.<br />Если уж "припечёт", то лучше breakpoint выставить.<br /><br />«перечитал несколько раз код. непривычно, но круто.. наверное. особенно, если делать ставку на поддержку различных субд. <br />а это пример из реального приложения?»<br />-- Да, это пример из реального приложения. И это действительно СУБД-независимый код.<br />Действительно, поначалу непривычно, но не в большей степени, чем замыкания и разные трюки с интерфейсами.<br />Это всего лишь последовательный вызов методов, каждый из которых (обычно) возвращает ссылку на экземпляр класса, из которого он вызван.NameRechttps://www.blogger.com/profile/00070033877714975718noreply@blogger.comtag:blogger.com,1999:blog-1453949493029009080.post-14355070636077252352014-04-26T00:10:24.475+03:002014-04-26T00:10:24.475+03:00перечитал несколько раз код. непривычно, но круто....перечитал несколько раз код. непривычно, но круто.. наверное. особенно, если делать ставку на поддержку различных субд.<br />а это пример из реального приложения?Николай Зверевhttps://www.blogger.com/profile/08965247674233981930noreply@blogger.comtag:blogger.com,1999:blog-1453949493029009080.post-71442114014053605012014-04-25T23:50:27.563+03:002014-04-25T23:50:27.563+03:00вот расскажите пожалуйста, как вы ходите отладчик...вот расскажите пожалуйста, как вы ходите отладчиком по этим текучим интерфейсам?Николай Зверевhttps://www.blogger.com/profile/08965247674233981930noreply@blogger.com