LCConnection

Тема в разделе "Lotus - Программирование", создана пользователем VladSh, 16 дек 2009.

  1. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    LCConnection - родное Lotus'овское API для работы с реляционными базами данных (РДБ).
    По времени освоения ADO/ODBC и LCConnection одинаковы, потому добрый совет - не связывайтесь с ADO и ODBC, которые заточены чисто под винду, просто не тратьте время понапрасну.

    Старая тема: Использование, какие есть мнения?

    LCConnection'у всё равно куда писать, в db2, Oracle и т.д., т.к. это всё базы данных.
    Для знающих Java конечно же лучше уже разобраться с JDBC. Но преимущество LCConnection в том, что не нужно мудохаться подбирая драйвера под "свою" реляционку. Указываете тип РБД при открытии соединения, а он автоматом использует нужный драйвер, работающий именно с этой РДБ.

    Для использования этого механизма в LS-коде необходимо в разделе Options прописать строку:
    Код (Text):
    Uselsx "*lsxlc"
    По DECS'у немного (чтобы не размазывалось по форуму):
    Добавляйте, уточняйте (лучше в личку, я здесь выложу).

    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">С чего начиналась данная тема...</div></div><div class="sp-body"><div class="sp-content">Вопрос по LSX. Подключаюсь к БД Oracle и нужно в 2 разные таблицы сделать по записи.
    Так вот, нужно чтобы гарантированно записать эти 2 записи, а не одну (к примеру, процесс оборвался).

    Алгоритм примерно должен быть такой (правильно ли я понимаю?):

    'Указываю 1-ю таблицу, в которую собираюсь писать:
    LCConnection.metadata = "TABLE1"

    'Создаю запись, заполняю поля...

    'Указываю 2-ю таблицу, в которую собираюсь писать:
    LCConnection.metadata = "TABLE2"

    'Создаю запись, заполняю поля...

    Есть несколько примеров, в них используется:
    Call LCConnection.Call(RecordFieldList, 1, Nothing)
    или
    Call LCConnection.Insert(RecordFieldList)
    Не совсем понятно, какой комадной всё-таки надо производить запись.. в чём тонкость?

    Т.к. у меня 2 записи, то нужен:
    Call LCConnection.Action(LCACTION_COMMIT)
    но непонятно, как отключить автоматический Commit при записи данных.

    Буду рад любой помощи!
     
  2. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    Нашёл в редбуке Implementing IBM Lotus Enterprise Integrator 6 (sq246067.pdf) такую главу:
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">9.3.9 Control Commit and Rollback</div></div><div class="sp-body"><div class="sp-content">You may have applications that require that you update multiple records at a time and
    complete all the updates before you commit any of them. This may especially be the case
    when there’s data in multiple tables and you need to commit your changes only once the data
    in all the tables are in a consistent state.

    The LCConnection class contains properties that let you control when commits happen. The
    LCConnection.CommitFrequency property can be used to control how frequently commits
    happen in that connection — a value of zero makes the connector not commit until you
    explicitly tell it to using the LCConnection.Action method.

    Normally, if your script is accessing data in multiple tables (or views) of the same database,
    you might create a separate LCConnection object for each table. This saves you having to
    change the Metadata property as you switch among the tables. However, if you use more
    than one LCConnection to do updates, then there’s not a way to guarantee commit of all the
    updates. If it’s critical that commits on multiple tables happen simultaneously (or that you be
    able to roll them all back), then you must use a single LCConnection object for all your
    operations, and use the CommitFrequency property and Action method as described above
    to control when commits happen.

    Example 9-1 Insert records into two tables and commit them simultaneously
    Код (Text):
    Function InsertDogData(con As LCConnection, dogRec As LCFieldList, awardRecs As LCFieldList, awardCount As Long) As Integer
    On Error Goto HandleError

    con.CommitFrequency = 0 ‘ only commit when we say to commit.
    con.Metadata = ”DOGS”
    con.Insert dogRec
    con.Metadata = ”DOGSHOWAWARDS”
    con.Insert awardRecs, 1, awardCount
    con.Action LCACTION_COMMIT ‘ commit changes to both tables.
    InsertDogData = 1 ‘ code for success
    Exit Function

    HandleError:
    ‘ In case of error, roll back any changes already made.
    con.Action LCACTION_ROLLBACK
    InsertDogData = 0 ‘ code for failure
    Exit Function
    End Function
    Добавлено:

    До того, как нашёл этот redbook, в Lotus Connectors and Connectivity Guide (help\lccon.nsf) в документе Fields in the LEI Connection Document нашёл переключатель Commit Options, содержащий следующие значения:
    - Commit At Disconnect;
    - Commit Every N Operations;
    - Commit Every Operation.

    Описание Commit At Disconnect: Enable this option to commit changes to the database as the database is being disconnected at the end of the operation. This is the default Commit option.

    Подумал, что по аналогии так и должно быть, т.е. началом транзакции можно считать вызов метода LCConnection.Connect(), а окончанием транзакции - LCConnection.Disconnect(). Оказалось, что всё так и есть, - записи в таблице сохраняются после вызова метода Disconnect. В пределах одной таблицы это работает на ура и без вызовов метода LCConnection.Action(LCACTION_...).
    Если нужно гарантированное одновременное внесение изменений в разные таблицы, то используем алгоритм, описанный в редбуке.

    N.B.: В мануалах встречал в коде, обрабатывающем ошибки, вызов действия LCACTION_TRUNCATE. После его использования очистилась вся текущая таблица, т.е. все данные, которые там были ранее - до моей записи! Использовать, когда создал таблицу, начал писать данные, но возникла ошибка и нужно быстро "обнулить" данные.

    Правильный код обработчика ошибок:
    Код (Text):
    If LCConnection.IsConnected Then
    Call LCConnection.Action(LCACTION_ROLLBACK)
    Call LCConnection.Action(LCACTION_CLEAR)
    End If
     
  3. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    Продолжаю писать сюда эссе "по чужим граблям")))

    Ещё одна проблема была... при записи вот таким кодом:
    Код (Text):
    Set LCRecord = New LCFieldList
    Set LCField = LCRecord.Append(fieldName, dataType)
    '...
    'а затем:
    Call LCConnection.Insert(LCRecord)
    вылетала ошибка 12546: "Field type mismatch: 'FIELDNAME' Source Connector field is type Integer, Target Connector field is type Text, Connector".

    Причина: такое происходит, когда в записи есть, к примеру 4 поля, а я, методом LCConnection.Insert(LCFieldList), записываю 1-е, 2-е и 4-е. Хотя обращаюсь по имени поля, но почему-то происходит "сдвиг" поля в записи с 4-го на 3-е (пропущенное).

    Workaround: если в записи есть 6 полей, но мне в данный момент нужно записывать 1-е, 2-е и 4-е поля, то я должен записать, как минимум, все поля с 1-го по 4-е.

    Решение (из того же монструозного редбука):
    Кстати, это свойство не описано в документации и не видно у объекта в отладчике ;)
     
  4. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    Метод Fetch, в отличие от простого перебора, как написано в хэлпе, ещё и вытягивает данные в LCFieldList.
    Переменная типа LCFieldList при
    Код (Text):
    Dim LCRecord As New LCFieldList
    тупо пуста, до тех пор, пока не сделаешь Fetch.
    Т.о. с "рекордом" (переменной типа LCFieldList) можно работать только ПОСЛЕ Fetch, ДО - бесполезно.
     
  5. Xalet

    Xalet Well-Known Member

    Регистрация:
    8 авг 2008
    Сообщения:
    410
    Симпатии:
    0
    Я немного не по теме. Никак не нахожу, как через коннектор функцию запустить Оракл. Скажем с процедурами нет проблем, например:

    Код (LotusScript):
    con.Procedure="SOME_PROC"

    con.Fieldnames="status, status_msg"


    Set Parm=Parms.Append("some_parm", LCTYPE_TEXT)
    Parm.text=FormatNumber("some_text","")


    Call Con.Call (Parms, 1, Result)

    Set fld = Result.Lookup ("status")
    Set fld2 = Result.Lookup ("status_msg")
    If (Con.Fetch (Result) > 0) Then
    status$ = fld.value(0)
    msg$ = fld2.value(0)
    End If
    А вот с функциями пока не понял, как можно. И можно ли вообще.
     
  6. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    Если запускаешь процедуру, то Оракл значит уже запущен.
    Не понял вопроса.

    Кусок, выпиленный из класса:
    Код (Text):
    %REM
    Function ExecuteProcedure
    Description: выполнение хранимой процедуры с обработкой ошибок
    %END REM
    Private Function ExecuteProcedure(sqlQuery As String, LCRecord As LCFieldList) As Boolean
    Set LCRecord = New LCFieldList

    bResult = Me.m_LCConnector.LCC.Execute(sqlQuery, LCRecord)
    If bResult Then
    Me.ExecuteProcedure = True

    'Else
    '   Call RTE.AddScalar("sqlQuery", sqlQuery)
    '   Call RTE.WriteError("Ошибка выполнения хранимой процедуры: неверный запрос", 1111, 0, False)
    End If
    End Function
    закоменчено потому, что при bResult = True не всегда всё хорошо. Например, у меня был такой момент, что синтаксис LND посчитал правильным, а Оракл в LCRecord вернул пустоту, только потому, что в конце выражения не стояла точка с запятой. Ну и ещё подобные странности бывают (ORA-Error, например, генерится)...

    В LCRecord возвращаются записи, т.е. грубо говоря это можно считать функцией :lovecodeby:
    Чтобы точно проверить, правильно ли всё выполнилось, надо чтобы программист-ораклоид так написал хранимую процедуру, чтобы она всегда возвращала LCRecord, в который добавлял какое-нибудь поле с условным именем, в которое писать результат (1 - значит True, 0 - False), а на выходе уже его анализировать.
     
  7. Xalet

    Xalet Well-Known Member

    Регистрация:
    8 авг 2008
    Сообщения:
    410
    Симпатии:
    0
    Похоже плохо вопрос сформулировал.

    С Oracle все хорошо и все обрабатывается. В Oracle есть процедуры и функции:

    Код (Text):
    procedure some_proc
    as
    parm number;
    begin
    some_code;
    end;

    FUNCTION                "some_func"
    ( parm        IN NUMBER )
    RETURN NUMBER
    IS
    BEGIN
    some_code;
    RETURN some_result;
    END;
    С процедурами работать через коннектор очень удобно(см код выше). Есть ли что-то подобное и для функций(я не нашел)? Конечно написать кусок SQL и запустить через Execute всегда можно, но это не так удобно.
     
  8. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    А какой смысл вызова оракловых функций из LND?
    Оракловые функции можно вызывать из хранимых процедур, а хранимые процедуры вызывать из LND, получая результат в LCFieldList, что почти тоже самое, что вызов функции.
    Смысл вызова хранимых процедур: это или выполнение каких-то действий без получения результата либо получение результата в LCFieldList.

    Я не видел в документации, чтобы что-то было для функций, везде речь идёт о 'хранимых процедурах'. Могу предположить, что можно вызвать с помощью Execute и функцию, но, думаю, что результат LCFieldList будет пустой, или ошибка вылетит. Но о5 же, не вижу в этом смысла.
     
  9. Xalet

    Xalet Well-Known Member

    Регистрация:
    8 авг 2008
    Сообщения:
    410
    Симпатии:
    0
    Да. Именно так и сделал. Просто функции были в Оракле готовы, а процедур не было.

    Вот и я поискал и ничего не нашел. Собственно и спрашивал чтобы узнать, плохо искал или на самом деле нет.

    Спасибо за ответы.
     
  10. Cleric-Lviv

    Cleric-Lviv Lotus team
    Lotus team

    Регистрация:
    3 янв 2008
    Сообщения:
    605
    Симпатии:
    0
    VladSh

    скажите пожалуста, пробовали ви перед тем как записать дание в таблицу обнулить ее???

    сначала
    DELETE * FROM table_name
    потом
    Call connection.Insert(LCRecord)

    у мну не получается удалить все записи из таблици.....
     
  11. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    Cleric-Lviv
    См. 2-й постинг этой темы.
     
  12. Cleric-Lviv

    Cleric-Lviv Lotus team
    Lotus team

    Регистрация:
    3 янв 2008
    Сообщения:
    605
    Симпатии:
    0
    VladSh


    Большое Спасибо!
     
  13. VladSh

    VladSh начинающий
    Lotus team

    Регистрация:
    11 дек 2009
    Сообщения:
    1.251
    Симпатии:
    2
    Давно хотел что-то поконкретнее выложить, чтобы люди не мучились с виндо-пердуляторами.. да и смешно бывает, когда некто любит туману напустить, типа супер-пупер зашифрованые мега-специалисты))
    Вот, выдалось время, и нате - примеры подключения, записи, вызова хранимых процедур, чтения:

    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Функция создания подключения</div></div><div class="sp-body"><div class="sp-content">
    Код (Text):
    %REM
    Function LCConnect
    Description: Подключение к реляционной базе данных (основная функция)
    %END REM
    Function LCConnect(sDbType As String, sHost As String, sLogin As String, sPassword As String) As LCConnection
    Dim LCC As LCConnection
    On Error Goto ErrH

    Set LCC = New LCConnection(sDbType)     'передаётся тип БД

    If Not LCC Is Nothing Then
    Select Case LCase(sDbType)      'Иначе на Database вылетает ошибка "Method does not exist"!
    Case "db2":
    LCC.Database = sHost
    Case Else
    LCC.Server = sHost
    End Select
    LCC.UserId = sLogin
    LCC.Password = sPassword
    Call LCC.Connect()

    If LCC.IsConnected Then Set LCConnect = LCC
    End If

    Exit Function

    ErrH:
    'пишем в лог ошибку...
    Exit Function
    End Function
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Класс LSXLCRdbWriter</div></div><div class="sp-body"><div class="sp-content">
    Код (Text):
    %REM
    Class LSXLCRdbWriter
    Description: Настраиваемая запись данных в РДБ с помощью LSXLC
    %END REM
    Class LSXLCRdbWriter
    Private LCC As LCConnection
    Private LCRecord As LCFieldList
    Private LCErr As Integer

    Sub New(LCC As LCConnection)
    Set Me.LCC = LCC.Copy()
    Me.LCC.CommitFrequency = 0      'only commit when we say to Commit
    End Sub


    %REM
    Property Set SetTable
    Description: Устанавливает текущее имя таблицы для записи
    %END REM
    Property Set SetMetadata
    Me.LCC.metadata = SetMetadata
    End Property


    %REM
    Property Set MapByName
    Description: Устанавливает соединению свойство записи данных по наименованиям полей, а не по порядку, как установлено по умолчанию
    %END REM
    Property Set MapByName As Boolean
    Me.LCC.MapByName = MapByName    'so that we don’t have to give a value for every field!
    End Property


    %REM
    Sub CreateRecord
    Description: Создание пустого объекта новой записи
    %END REM
    Public Sub RecordCreate()
    Set Me.LCRecord = New LCFieldList
    End Sub


    %REM
    Function Run
    Description: Сохранение текущей записи в текущей таблице
    %END REM
    Public Function RecordComplete() As boolean
    On Error GoTo ErrH

    If Me.LCErr = 0 Then
    Call Me.LCC.Insert(Me.LCRecord)
    Me.RecordComplete = True
    End If

    Exit Function

    ErrH:
    Call Me.SaveError(Error$, Err, Erl)
    Exit Function
    End Function


    %REM
    Sub AppendFieldValue
    Description: Добавляет объект поля записывает его значение в текущую запись
    %END REM
    Public Sub AppendFieldValue(RDB_FieldName As String, LCFieldType As Long, Value As Variant)
    Dim LCField As LCField
    On Error GoTo ErrH

    Set LCField = Me.LCRecord.Append(RDB_FieldName, LCFieldType)
    LCField.Value = Value
    Exit Sub

    ErrH:
    Me.LCErr = Err
    Call Me.SaveError(Error$, Err, Erl)
    Exit Sub
    End Sub


    %REM
    Sub ConnectionClose
    Description: Завершает работу с RDB, подтверждая внесённые изменения
    %END REM
    Public Sub ConnectionClose()
    Call Me.LCC.Action(LCACTION_COMMIT) 'commit changes to all tables
    Call Me.LCC.Disconnect()
    End Sub


    %REM
    Sub SaveError
    Description: Отмена всех действий по записи в RDB, сохранение информации об ошибке
    %END REM
    Private Sub SaveError(pError As String, pErr As Long, pErl As Integer)
    Call Me.LCC.Action(LCACTION_ROLLBACK)
    Call Me.LCC.Action(LCACTION_CLEAR)
    Call Me.LCC.Disconnect()

    'пишем в лог ошибку...
    End Sub

    End Class
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Пример записи в 2 таблицы с общим Commit'ом (тоже выпилено из ещё одного своего класса, так что звыняйтэ)</div></div><div class="sp-body"><div class="sp-content">
    Код (Text):
    Dim oLccW As New LSXLCRdbWriter(Me.m_LCConnector.LCC)

    'Запись данных (в 1-ю таблицу)
    oLccW.SetMetadata = "TABLE_DATA"
    For i% = 0 To UBound(ArrContent)
    Call oLccW.RecordCreate()
    'пишите что хотите...
    'Call oLccW.AppendFieldValue("ESSENCE_NAME", LCTYPE_TEXT, Me.m_ndSource.GetItemValue("Form")(0))
    'Call oLccW.AppendFieldValue("NUMBER_REC", LCTYPE_INT, i%)
    'Call oLccW.AppendFieldValue("DATE_TIME", LCTYPE_DATETIME, Now)
    'Call oLccW.AppendFieldValue("VALUE", LCTYPE_TEXT, ArrContent(i%))
    If Not oLccW.RecordComplete() Then Exit Function
    Next

    'Запись ссылок на данные (во 2-ю таблицу)
    oLccW.SetMetadata = "TABLE_LINKS"
    Call oLccW.RecordCreate()
    'также пишите что хотите...
    'Call oLccW.AppendFieldValue("GUID", LCTYPE_TEXT, "...")
    'Call oLccW.AppendFieldValue("DATE_TIME", LCTYPE_DATETIME, Now)
    If Not oLccW.RecordComplete() Then Exit Function

    Call oLccW.ConnectionClose()
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Кусок класса ReqLCProcedureBase</div></div><div class="sp-body"><div class="sp-content">
    Код (Text):
    %REM
    Function ExecuteProcedure
    Description: выполнение хранимой процедуры с обработкой ошибок
    %END REM
    Private Function ExecuteProcedure(sqlQuery As String, LCRecord As LCFieldList) As Boolean
    Set LCRecord = New LCFieldList

    bResult = Me.m_LCConnector.LCC.Execute(sqlQuery, LCRecord)
    'тут надо самим определять, ошибочный вызов или нет (выше об этом писал...)
    If bResult Then
    Me.ExecuteProcedure = True
    Else
    'пишем в лог ошибку...
    'Call RTE.AddScalar("sqlQuery", sqlQuery)
    'Call RTE.WriteError("Ошибка выполнения хранимой процедуры: неверный запрос", ERRc1111, 0, False)
    End If
    End Function


    %REM
    Function GetFieldValue
    Description:    выполняет хранимую процедуру и возвращает значение поля 1-й записи
    NB: - результат проверять IsEmpty
    - если нужно чтобы возвратило массив значений, то в FieldIndex передаём -1
    %END REM
    Private Function GetFieldValue(sqlQuery As String, FieldName As String, FieldIndex As Integer) As Variant
    Dim LCRecord As LCFieldList
    Dim LCField As LCField

    If Me.ExecuteProcedure(sqlQuery, LCRecord) Then

    While Me.m_LCConnector.LCC.Fetch(LCRecord)  'Fetch вытягивает данные в LCRecord
    Set LCField = LCRecord.Lookup(FieldName)    'получаем поле по имени
    If Not LCField Is Nothing Then
    If FieldIndex >= 0 Then
    Me.GetFieldValue = LCField.Value(FieldIndex)
    Else
    Me.GetFieldValue = LCField.Value()
    End If
    Else
    'сами записывайте ошибку как хотите...
    'Call RTE.AddScalar("sqlQuery", sqlQuery)
    'Call RTE.AddScalar("FieldName", FieldName)
    'Call RTE.AddScalar("FieldIndex", FieldIndex)
    'Call RTE.WriteError("Ошибка выполнения хранимой процедуры: в возвращаемой записи отсутствует необходимое поле", 0, 0, False)
    End If
    Wend

    End If
    End Function
    Добавлено:
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Дискуссия по ошибке "Assignment of a NULL value to a NOT NULL column"</div></div><div class="sp-body"><div class="sp-content">
    Спасибо, ребята!
     
  14. Nikitoss

    Nikitoss Гость

    Какие ещё причины ошибки "№217 Error creating product project" могут быть?
    Кроме не не подключения Uselsx "*lsxlc" конечно=)

    Dim LCC As LCConnection
    Set LCC = New LCConnection("SQL")
     
  15. RAJ

    RAJ Well-Known Member

    Регистрация:
    17 янв 2007
    Сообщения:
    440
    Симпатии:
    0
    клиент установлен без DECS
     
  16. Gandliar

    Gandliar Well-Known Member

    Регистрация:
    16 фев 2004
    Сообщения:
    222
    Симпатии:
    0
    А можно ли подключиться через lcconnection к mySql

    что для этого необходимо?
     
  17. lmike

    lmike нет, пердело совершенство
    Команда форума Lotus team

    Регистрация:
    27 авг 2008
    Сообщения:
    6.079
    Симпатии:
    300
    через... ОДБЦ, с вытекающими...
    потому - jdbc - тръу :icq:
     
  18. Кирилл Шваб

    Кирилл Шваб Well-Known Member

    Регистрация:
    30 июн 2006
    Сообщения:
    144
    Симпатии:
    4
    Gandliar,

    Код (LotusScript):
    Dim connection As LCConnection
    Set connection = New LCConnection("odbc2")
     
  19. Constantin A Chervonenko

    Constantin A Chervonenko Well-Known Member

    Регистрация:
    30 май 2006
    Сообщения:
    1.288
    Симпатии:
    0
    Нет такого коннектора "SQL"
    Есть (м.б.) "db2", "oracle", "odbc2", "oledb", ещё кое-что..
     
  20. Serduko

    Serduko Well-Known Member

    Регистрация:
    11 окт 2011
    Сообщения:
    174
    Симпатии:
    0
    При подключении к MSSQL, при доменной авторизации, не коннектит и пишет ошибку "недопустимая спецификация авторизации". Что делать?

    Нашел:

    Код (LotusScript):
    LCC.Auth_Integrated = "SSPI"
     
Загрузка...
Похожие Темы - LCConnection
  1. nayke
    Ответов:
    11
    Просмотров:
    3.696
  2. sanch
    Ответов:
    42
    Просмотров:
    11.969

Поделиться этой страницей