Рассылка закрыта
При закрытии подписчики были переданы в рассылку "Секреты бизнеса. Предприниматели рассказывают..." на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
← Апрель 2010 → | ||||||
1
|
2
|
3
|
4
|
|||
---|---|---|---|---|---|---|
6
|
7
|
8
|
9
|
10
|
11
|
|
12
|
13
|
14
|
15
|
16
|
17
|
18
|
19
|
20
|
21
|
22
|
23
|
24
|
25
|
26
|
27
|
28
|
29
|
Статистика
-21 за неделю
Создаем свою информационную систему
Создаем свою информационную системуИнвентаризация. 1
Итак сегодня попробуем обсудить конкретный проект и перепетии его реализации. Проект относительно свежий, и поэтому еще не изгладились впечатления от его создания. Начну с того, что сам проект относительно бюджетный для заказчика, что в текущих условиях вполне оправдано.
Суть в слеующем. Необходимость проведения инвентаризации основных средств ( ну и материалов) является требованием, существующим, как и весь бухгалтерский учет, за счет узаконенной нагрузки на бизнес.
Ситуация в общем-то банальная, для больших предприятий. На самом деле в рамках «предприятия» существует много юридических лиц, которые территориально находятся в одном месте. Огромное количество объектов, которые можно отнести к материалам и основным средствам. Ну и нам надо, хотя бы раз в год проверить наличие этих средств, т.е. сравнить их с данными учета. Итогом работы является документ(ы) в котрых написано было столько-то, найдено – столько-то. Но это только начало. Раз уж делается программа, то хочется вести учет реального движения материалов, не в смысле производства, а в нормальном человеческом смысле. За этот стол отвечает Иванов, за омпьютер – Петров. Эти люди могут двигаться по служебной лестнице переводиться и пересаживаться с места на место, увольняться. А еще они могут что-то сломать, или потерять….
Для «разминки» заказчик хотел бы увидеть не просто программу, но и провести тестовую проверку системы, ну скажем на 3000 объектах.
Поскольку объекты разбросаны, то для инвентаризации должны использоваться терминалы сбора данных, ну и соответственно штрихкодирование, чтобы исключить ошибки ввода.
Это я пока привожу только начальную постановку, и не совсем полную.
Ну чтоже главное ввязаться в бой.
Через пару месяцев разговоров вокруг да около проект вошел в стадию реализации.
Первой «засадой» оказалось требование от IT службы, о том что нельзя ставить никакого дополнительного софта кроме самой программы, в том числе и на сервер, причем там особо было указано, что MS SQL Server и .Net не должны устанавливаться.
Карта была разыграна очень просто, на обсуждение ТЗ посылается специалист из IT службы, Который соглашается, что в ТЗ разговор только про рабочие станции, а требование выдвигает начальник службы, который на этом обсуждении не был и ничего кроме ТЗ не признает. Как говорил Эзоп, - Отсюда мораль: Закрепляйте все в ТЗ! Никакие протоколы обсуждения, даже подписанные вам скорее всего не помогут.
Итак мы оказались перед необходимостью использовать бесплатную базу данных, которую относительно просто развернуть из дистрибутива.
Если честно, то я подозревал что будет именно так. И, слава Богу, наш подход не привязан жестко к типу базы данных. Да, конечно, нам пришлось срочно собирать генератор для новой базы. А выбрали мы PostgreSQL. И, конечно, имея опыт создания генераторов это было не так долго. И, самое интересное, что мы получили некий козырь перед заказчиком, потому как вписались в их требования, точно зная, что в ТЗ есть относительно плохо проработанные места и нам будет чем «ответить» на страшном суде.
Техническая сторона реализации генератора.Первое, что надо сделать - это понять на что похож подход при реализации базы данных. Скажем у ORACLE довольно специфичный подход к компиляции зависимых процедур и там очень жестко надо следить ( или бороться) с тем чтобы все процедуры от которых зависит текущая были уже известны компилятору. Про это можно будет поговорить отдельно, но в частности в ORACLE сильно спасает объявление заголовков package.
Затем надо построить правилное отображение используемых в моделировании типов данных на хранилище.
Вот пример одно из вариантов такого отображения:
Затем надо «построить» генератор базы данных
Для примера я приведу три идентичных фрагмента генератора для разных типов баз данных
PostgreSQLPrivate Sub CreateBriefProc(os As PART) DebugOutput "POSTGRESGEN.CreateBriefProc:start " Dim st As PART Set st = os Dim chos As PART, i As Long, j As Long, f As FIELD Dim s As Writer Set s = New Writer On Error GoTo bye s.putBuf "" s.putBuf " create or replace function " & VF(os.Name) & "_BRIEF (" s.putBuf " aCURSESSION uuid," s.putBuf " a" & VF(os.Name) & "id uuid" s.putBuf ") returns varchar as $$" s.putBuf "declare" s.putBuf " aBRIEF varchar(255);" s.putBuf " aaccess integer;" s.putBuf " atmpStr varchar(255);" s.putBuf " atmpID uuid;" s.putBuf " existsCnt integer;" s.putBuf "begin" s.putBuf " -- checking the_session --" s.putBuf " select count(*) into existsCnt from the_session where the_sessionid=acursession and closed=0 ;" s.putBuf "if existsCnt=0" s.putBuf " then" s.putBuf " perform raise_application_error(-20000,'Сессия уже завершена.');" s.putBuf " return '';" s.putBuf " end if;"
s.putBuf "if a" & VF(os.Name) & "id is null then aBRIEF:=''; return aBrief; end if;"
s.putBuf " -- Brief body -- " s.putBuf "select count(*)into existsCnt from " & VF(os.Name) & " where " & VF(os.Name) & "ID=a" & VF(os.Name) & "ID;" s.putBuf "if existsCnt >0" s.putBuf " then" s.putBuf " aBRIEF:= " & VF(os.Name) & "_BRIEF_F(a" & VF(os.Name) & "id);" s.putBuf "else" s.putBuf " aBRIEF:= 'неверный идентификатор';" s.putBuf "end if;" s.putBuf " aBRIEF:=substr(aBRIEF,1,255);" s.putBuf "return aBrief;" s.putBuf "end; $$ language 'plpgsql';" s.putBuf "GO"
o.Module = "--functions.Type.Body" o.Block = "--" & ot.Name o.OutNL s.getBuf DebugOutput "POSTGRESGEN.CreateBriefProc:done " Set s = Nothing Exit Sub bye: 'Resume Set s = Nothing End Sub
MS SQLPrivate Sub CreateBriefProc(os As PART) DebugOutput "SQLGEN.CreateBriefProc:start " If os.PartType = PartType_Rassirenie Then Exit Sub End If
Dim st As PART Set st = os Dim chos As PART, i As Long, j As Long, f As FIELD Dim s As Writer Set s = New Writer CreateBriefFunc os log = log & vbCrLf & "-CreateBriefProc " & os.Name On Error GoTo bye s.putBuf "" s.putBuf procDropSQL(os.Name & "_BRIEF") s.putBuf "create proc " & os.Name & "_BRIEF (" s.putBuf " @CURSESSION uniqueidentifier," s.putBuf " @" & os.Name & "id uniqueidentifier," s.putBuf " @BRIEF varchar(4000) output" s.putBuf ") as " & " begin " s.putBuf "set nocount on" s.putBuf " declare @access int" s.putBuf " declare @tmpStr varchar(255)" s.putBuf " declare @tmpID uniqueidentifier" s.putBuf " -- checking session --" s.putBuf "if not exists( select 1 from the_session where the_sessionid=@cursession and closed=0 )" s.putBuf " begin" s.putBuf " raiserror('Сессия уже завершена.',16,1)" s.putBuf " return" s.putBuf " end" s.putBuf " declare @Lang2 varchar(25)" s.putBuf " select @Lang2=Lang from the_session where the_sessionid=@cursession"
s.putBuf "if @" & os.Name & "id is null begin set @BRIEF='' return end"
s.putBuf " -- Brief body -- "
s.putBuf "if exists(select 1 from " & os.Name & " where " & os.Name & "ID=@" & os.Name & "ID)" s.putBuf " begin" s.putBuf " -- verify access --" s.putBuf " select @tmpID =SecurityStyleID from " & os.Name & " where " & os.Name & "id=@" & os.Name & "ID" s.putBuf " exec CheckVerbRight cursession=@cursession,@Resource=@tmpID,@verb='BRIEF',@access=@access out " s.putBuf " if @access=0 " s.putBuf " begin" s.putBuf " raiserror('No access for BRIEF Structure=" & os.Name & "',16,1)" s.putBuf " return" s.putBuf " end" '''' 'MLF 's.putBuf " select BRIEF=dbo." & os.Name & "_BRIEF_F(@" & os.Name & "id)" s.putBuf " select BRIEF=dbo." & os.Name & "_BRIEF_F(@" & os.Name & "id, @Lang2)"
s.putBuf "end else begin" s.putBuf " set @BRIEF= 'неверный идентификатор'" s.putBuf "end" s.putBuf "set BRIEF=left(@BRIEF,4000)" s.putBuf "end "
s.putBuf "go" If (OptRights) Then s.putBuf "revoke all on [dbo].[" & os.Name & "_BRIEF] to [public]" s.putBuf "go" s.putBuf "grant execute on [dbo].[" & os.Name & "_BRIEF] to [public]" s.putBuf "go" End If
o.Module = "--Procedures" o.Block = "--TableProc" o.OutNL s.getBuf o.OutNL "GO" DebugOutput "SQLGEN.CreateBriefProc:done " Set s = Nothing Exit Sub bye: log = log & vbCrLf & "ERROR-" & Err.Description & "<--ERROR" 'Resume Set s = Nothing End Sub
ORACLEPrivate Sub CreateBriefProc(os As PART) DebugOutput "ORAGEN.CreateBriefProc:start " Dim st As PART Set st = os Dim chos As PART, i As Long, j As Long, f As FIELD Dim s As Writer Set s = New Writer On Error GoTo bye s.putBuf "" s.putBuf "procedure " & VF(os.Name) & "_BRIEF (" s.putBuf " aCURSESSION CHAR," s.putBuf " a" & VF(os.Name) & "id CHAR," s.putBuf " aBRIEF out varchar2" s.putBuf ") as " s.putBuf " aaccess integer;" s.putBuf " atmpStr varchar2(255);" s.putBuf " atmpID CHAR(38);" s.putBuf " existsCnt integer;" s.putBuf "begin" s.putBuf " -- checking the_session --" s.putBuf " select count(*) into existsCnt from the_session where the_sessionid=acursession and closed=0 ;" s.putBuf "if existsCnt=0" s.putBuf " then" s.putBuf " raise_application_error(-20000,'Сессия уже завершена.');" s.putBuf " return;" s.putBuf " end if;"
s.putBuf "if a" & VF(os.Name) & "id is null then aBRIEF:=''; return; end if;"
s.putBuf " -- Brief body -- " s.putBuf "select count(*)into existsCnt from " & VF(os.Name) & " where " & VF(os.Name) & "ID=a" & VF(os.Name) & "ID;" s.putBuf "if existsCnt >0" s.putBuf " then" s.putBuf " -- verify access --" s.putBuf " select SecurityStyleID into atmpid from " & VF(os.Name) & " where " & VF(os.Name) & "id=a" & VF(os.Name) & "ID;" s.putBuf " CheckVerbRight (acursession=>acursession,aThe_Resource=>atmpID,averb=>'BRIEF',aaccess=>aaccess); " s.putBuf " if aaccess=0 " s.putBuf " then" s.putBuf " raise_application_error(-20000,'No access for BRIEF Structure=" & VF(os.Name) & "');" s.putBuf " return;" s.putBuf " end if;" s.putBuf " aBRIEF:=func." & VF(os.Name) & "_BRIEF_F(a" & VF(os.Name) & "id);" s.putBuf "else" s.putBuf " aBRIEF:= 'неверный идентификатор';" s.putBuf "end if;" s.putBuf " aBRIEF:=substr(aBRIEF,1,255);" s.putBuf "end; "
o.Module = "--Procedures.Type.Body" o.Block = "--" & ot.Name o.OutNL s.getBuf DebugOutput "ORAGEN.CreateBriefProc:done " Set s = Nothing Exit Sub bye: 'Resume Set s = Nothing End Sub
Если вы внимательно посмотрите на эти фрагменты, то поймете, что они немного отличаются функционально, но очень близки, а если напряжетесь еще немного, то поймете, как работает уровень абстракции баз данных в нашем подходе. Да, просто формируется набор процедур, в который упакована нужная логика, но эти процедуры идентеичны по названиям и параметрам! Поэтому уже на уровне слоя баз данных можно спокойно работать с рзными источниками. И более того можно разрабатывать приложения не очень задумываясь над тем, на какой реально базе данных оно будет работать. Хотя это конечно небольшое лукавство… Иногда приходится писать что-то вроде этого: f = f & " and invi_DEF_EndDate<=" & IIf(Session.IsMSSQL, MakeMSSQLDate(fltr.dtpinvi_DEF_EndDate_LE.Value), IIf(Session.IsORACLE, MakeORACLEDate(fltr.dtpinvi_DEF_EndDate_LE.Value), MakePGSQLDate(fltr.dtpinvi_DEF_EndDate_LE.Value)))
Мне кажется, что для одного выпуска текст и так затянулся. Так что пока остановимся. Но обязательно продолжим разговор об этом проекте.
|
В избранное | ||