Имя: Пароль:
1C
1С v8
COMConnector + VB.NET 2010 , Проблема с функцией "Тип()"
0 Kyrill_F
 
03.02.16
12:11
Здравствуйте.
Пытаюсь работать с 1С 8.3 через ComConnector (Бухучет 3.0) из VB.NET. А именно - нужно сделать запрос и получить результаты.
В принципе все получается, запрос работает, данные возвращаются и т.д. Но есть проблема. Мне нужно определить тип данных в каждой колонке результата. Если я правильно понимаю, дла этого нужно использовать свойство СодержитТип().
Т.е. для первой колонки результата нужно проверять
Запрос.Выполнить.Колонки.Получить(0).СодержитТип(Тип("НазваниеТипа"))
Для того, чтобы это сделать, нужно сначала получить значение Тип("НазваниеТипа"), а потом уже передать его свойству СодержитТип()
Вот в этом и проблема. У меня не получается задействовать функцию Тип() через COM
Вот упрощенный кусок кода. Полный код с запросом не привожу чтобы не путуать, т.к. Функция "Тип" должна работать и сама по себе.

Dim ConnectionString as String="....."
Dim con As New COMConnector
Dim BuhRoot As Object = con.Connect(connectionString)
MsgBox(BuhRoot.NewObject("СистемнаяИнформация").ВерсияПриложения()) <-- тест подключения, все ок
Dim TestType as Object = BuhRoot.Тип("Число") <-- Здесь возникает ошибка Public member 'Тип' on type '_ComObject' not found
Пробовал через InvokeMethod - та же ерунда, не найдено.

Подскажите, пожалуйста, как получить это проклятое знчение? Может быть, есть какое-то другое представление, например константа, для описания типов "Строка", "Дата", "Число", чтобы подсунуть в качестве аргумента СодержитТип() ?

Спасибо.
1 mehfk
 
03.02.16
12:14
Type
2 Serginio1
 
03.02.16
12:18
Используйте внешние отчеты Как через оле задать отбор?
3 DmitrO
 
03.02.16
12:32
(0)функцию Тип через COM вызвать не удастся.
Дело в том что через COM доступны только "функции глобального контекста", и недоступны "встроенные функции". Это документировано.

Встроенные функции это СокрЛ, СокрП, СтрДлина и т.п. самые простые, которые вызывать в общем-то незачем. К сожалению Тип это тоже встроенная функция.

Раньше в синтакс-помощнике было видно какие функции у чему относятся, теперь это не видно.
4 Карупян
 
03.02.16
12:38
ВычислитьВыражение(Выражение) в базе - это ППЦ какая дыра в безопасности
5 Kyrill_F
 
03.02.16
12:39
(1) Пробовал, та же ошибка.
(3) Нда... Есть идея, как обойти проблему. У меня принципиальное ограничение - не лезть в конфигурацию.
6 DmitrO
 
03.02.16
12:39
Однако значение типа Тип через COM получить можно. Теми или иными способами.

Например используя объект ОписаниеТипов:

Описание = Новый ОписаниеТипов("СправочникСсылка.Номенклатура");
ТипНоменклатура = Описание.Типы().Получить(0);
7 Serginio1
 
03.02.16
12:40
(4) Внешние отчеты и так дыра
(5) Смотри 2 и будет тебе счастье
8 Карупян
 
03.02.16
12:41
Вот пример
v8: не получается через COM получить Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекци
COMCоединение.NewObject("ОписаниеТипов","ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений").Типы().Получить(0)
9 Kyrill_F
 
03.02.16
12:41
(6)  Меня именно простые типыф колонок интересуют ("Строка", "Число", "Дата")
10 Kyrill_F
 
03.02.16
12:42
(8) Не уверен, что понял, но попробую.
2 All забыл сказать, я не спец по 1С :)
11 DmitrO
 
03.02.16
12:46
(9)
Dim TestType as Object = BuhRoot.NewObject("ОписаниеТипов", "Число").Типы().Получить(0)
12 Kyrill_F
 
03.02.16
12:53
(11) (8) Спасибо огромное! Сейчас попробую. Вчитался в справочник, тоже увидел, что конструктор ОписаниеТипов допускает передачу типа в виде строки. Должно сработать.
13 Kyrill_F
 
03.02.16
16:01
Сработало.
Вот какая функция получилась, может пригодится кому...
Всем спасибо!

-----------------
    ''' <summary>
    ''' Выполнение запроса в 1С
    ''' </summary>
    ''' <param name="QueryText">Текст запроса на языке запросов 1С</param>
    ''' <returns>Возвращает результат запроса в виде System.Data.DataSet c единственной таблицей внутри</returns>
    ''' <remarks>Перед вызовом должен существовать корневой объект 1С в переменной BuhRoot</remarks>
    Public Function ExecuteQuery(QueryText As String) As DataSet

        Dim ResultDataSet As New DataSet
        Dim ResultTable As DataTable = ResultDataSet.Tables.Add

        Dim BuhTypeStr As Object = GetBuhType("Строка")
        Dim BuhTypeNum As Object = GetBuhType("Число")
        Dim BuhTypeDat As Object = GetBuhType("Дата")

        Dim BuhQuery As Object = BuhRoot.NewObject("Запрос")
        BuhQuery.Текст = QueryText

        Dim BuhExecQuery As Object = BuhQuery.Выполнить()
        Dim BuhResultColumns As Object = BuhExecQuery.Колонки()
        Dim BuhColumnCount As Integer = BuhResultColumns.Количество()

        Dim BuhCurrentColumn As Object
        Dim BuhColumnTypes As Object
        Dim NewDataRow As DataRow
        Dim ColumnType As System.Type

        For idx As Integer = 0 To BuhColumnCount - 1
            BuhCurrentColumn = BuhResultColumns.Получить(idx)

            LogWrite(BuhCurrentColumn.Имя)

            BuhColumnTypes = BuhCurrentColumn.ТипЗначения

            With BuhColumnTypes
                If .СодержитТип(BuhTypeStr) Then
                    ColumnType = Type.GetType("System.String")
                ElseIf .СодержитТип(BuhTypeDat) Then
                    ColumnType = Type.GetType("System.DateTime")
                ElseIf .СодержитТип(BuhTypeNum) Then
                    ColumnType = Type.GetType("System.Decimal")
                Else
                    ColumnType = Type.GetType("System.String")
                End If
            End With
            ResultTable.Columns.Add(BuhCurrentColumn.Имя, ColumnType)
        Next

        Dim BuhResultRows As Object = BuhExecQuery.Выбрать()
        Dim RowCount As Integer
        Integer.TryParse(BuhResultRows.Количество(), RowCount)
        For i As Integer = 1 To RowCount
            BuhResultRows.Следующий()
            NewDataRow = ResultTable.NewRow
            For idx As Integer = 0 To BuhColumnCount - 1
                Try
                    NewDataRow(idx) = BuhResultRows.Получить(idx)
                Catch ex As Exception
                End Try
            Next
            ResultTable.Rows.Add(NewDataRow)
        Next
        Return ResultDataSet
    End Function
14 Serginio1
 
03.02.16
16:14
(13) Как создать DataTable из 1С

Функция ПолучитьОписаниеТиповСтроки(ДлинаСтроки) Экспорт

    Возврат Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(ДлинаСтроки, ДопустимаяДлина.Переменная));

КонецФункции // ПолучитьОписаниеТиповСтроки()

// Служебная функция, предназначенная для получения описания типов числа, заданной разрядности.
//
// Параметры:
//  Разрядность             - число, разряд числа.
//  РазрядностьДробнойЧасти - число, разряд дробной части.
//
// Возвращаемое значение:
//  Объект "ОписаниеТипов" для числа указанной разрядности.
//
Функция ПолучитьОписаниеТиповЧисла(Разрядность, РазрядностьДробнойЧасти = 0, ЗнакЧисла = Неопределено) Экспорт

    Если ЗнакЧисла = Неопределено Тогда
        КвалификаторЧисла = Новый КвалификаторыЧисла(Разрядность, РазрядностьДробнойЧасти);
    Иначе
        КвалификаторЧисла = Новый КвалификаторыЧисла(Разрядность, РазрядностьДробнойЧасти, ЗнакЧисла);
    КонецЕсли;

    Возврат Новый ОписаниеТипов("Число", КвалификаторЧисла);

КонецФункции // ПолучитьОписаниеТиповЧисла()

Функция ПолучитьОписаниеТиповДаты(ЧастиДаты) Экспорт

    Возврат Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты));

КонецФункции // ПолучитьОписаниеТиповДаты()

Функция ПолучитьЗначение(Колонка,Сч)

Тип=Колонка.ТипЗначения;
Если Тип=Неопределено Тогда
возврат сч
КонецЕсли;

Если тип.Типы().Количество()>1 Тогда
    возврат сч
КонецЕсли;

Тип1=тип.Типы()[0];

Если Тип1=Тип("Число") Тогда
    Квалификатор=Тип.КвалификаторыЧисла;
    Если Квалификатор.РазрядностьДробнойЧасти>0 Тогда
        возврат Окр(сч+1/сч,Квалификатор.РазрядностьДробнойЧасти);
    КонецЕсли;
    
    Разрядность=Квалификатор.Разрядность;
    Если Разрядность<10 Тогда
        возврат сч
    ИначеЕсли Разрядность<19 Тогда    
        возврат сч
    Иначе
        возврат сч
    КонецЕсли;
    
КонецЕсли;

Если Тип1=Тип("Строка") Тогда
возврат Строка(сч)
ИначеЕсли Тип1=Тип("Дата") Тогда
возврат ТекущаяДата()
КонецЕсли;

return сч

КонецФункции // ПолучитьЗначение()

Процедура КнопкаСформироватьНажатие(Кнопка)
    // Вставить содержимое обработчика.
    
    Тз=новый ТаблицаЗначений;
    Колонки=Тз.Колонки;
    Колонка=Колонки.Добавить("КолонкаЧисло",ПолучитьОписаниеТиповЧисла(9,0));
    Сообщить(ПолучитьТипКолонкиДляДТ(Колонка));
    
    Колонка=Колонки.Добавить("КолонкаЧисло2",ПолучитьОписаниеТиповЧисла(18,0));
    Сообщить(ПолучитьТипКолонкиДляДТ(Колонка));

    Колонка=Колонки.Добавить("КолонкаЧисло3",ПолучитьОписаниеТиповЧисла(20,0));
    Сообщить(ПолучитьТипКолонкиДляДТ(Колонка));
    
    Колонка=Колонки.Добавить("КолонкаЧисло4",ПолучитьОписаниеТиповЧисла(7,2));
    Сообщить(ПолучитьТипКолонкиДляДТ(Колонка));

   Колонка=Колонки.Добавить("КолонкаДата",ПолучитьОписаниеТиповДаты(ЧастиДаты.ДатаВремя));
    Сообщить(ПолучитьТипКолонкиДляДТ(Колонка));
    
    Колонка=Колонки.Добавить("КолонкаСтрока",ПолучитьОписаниеТиповСтроки(0));
    Сообщить(ПолучитьТипКолонкиДляДТ(Колонка));


    Для Сч=1 По 10 Цикл
         Стр=Тз.Добавить();
        Для каждого Колонка Из Колонки Цикл
        
        Стр[Колонка.Имя]=ПолучитьЗначение(Колонка,сч);
        
        КонецЦикла;
    
    КонецЦикла;
    врап=новый COMОбъект("NetObjectToIDispatch45");
    Дт=СоздатьДТ(врап,Тз,"MyTable");
КонецПроцедуры
15 Serginio1
 
03.02.16
16:15
Функция ПолучитьТипКолонкиДляДТ(Колонка) Экспорт
Тип=Колонка.ТипЗначения;
Если Тип=Неопределено Тогда
возврат "System.Object"
КонецЕсли;

Если тип.Типы().Количество()>1 Тогда
    возврат "System.Object"
КонецЕсли;

Тип1=тип.Типы()[0];

Если Тип1=Тип("Число") Тогда
    Квалификатор=Тип.КвалификаторыЧисла;
    Если Квалификатор.РазрядностьДробнойЧасти>0 Тогда
        возврат "System.Decimal"
    КонецЕсли;
    
    Разрядность=Квалификатор.Разрядность;
    Если Разрядность<10 Тогда
        возврат "System.Int32"
    ИначеЕсли Разрядность<19 Тогда    
        возврат "System.Int64"
    Иначе
        возврат "System.Decimal"
    КонецЕсли;
    
КонецЕсли;

Если Тип1=Тип("Строка") Тогда
возврат "System.String"
ИначеЕсли Тип1=Тип("Дата") Тогда
возврат "System.DateTime"
КонецЕсли;

return "System.Object"
КонецФункции    

Функция СоздатьДТ(врап,Тз,ИмяТаблицы) Экспорт

     Колонки=Тз.Колонки;

     myTable=Врап.СоздатьОбъект("System.Data.DataTable, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",ИмяТаблицы);
     DataColumn=Врап.ПолучитьТип("System.Data.DataColumn");
     Columns= myTable.Columns;
     КоличествоКолонок=Колонки.Количество();
     Для каждого Колонка Из Колонки Цикл
    
          colItem =Врап.СоздатьОбъект(DataColumn,Колонка.Имя, Врап.ПолучитьТип(ПолучитьТипКолонкиДляДТ(Колонка)));
         Columns.Add(colItem);
    
     КонецЦикла;
    
//    rowArray =новый COMSafeArray("VT_VARIANT",КоличествоКолонок);//Врап.СоздатьМассив("System.Object",КоличествоКолонок);
    Rows=myTable.Rows;
    Для каждого стр Из Тз Цикл
          Row = myTable.NewRow();
        Для сч=0 По КоличествоКолонок-1 Цикл
            сообщить(стр[сч]);
        Row.set_Item(сч,стр[сч]);
          
      КонецЦикла;
      
Сообщить(Row.ToString());
//Rows.Add(Row);
врап.ВыполнитьМетод(Rows,"Add",Row);


    КонецЦикла;
    
    возврат myTable
КонецФункции
16 Serginio1
 
03.02.16
16:16
17 mehfk
 
03.02.16
16:19
Что, опять?
18 Serginio1
 
03.02.16
16:20
(17) Не опять, а снова
19 Kyrill_F
 
03.02.16
16:36
(14) (14) (16) Очень познавательно, спасибо.
20 Serginio1
 
03.02.16
16:41
(19) На здоровье!
(17) Видишь, не зря опять.
21 Kyrill_F
 
03.02.16
16:44
(13) Вверху забыл кусочек добавить (самый важный, из-за которго сыр-бор был)

    Private Function GetBuhType(TypeName As String) As Object
        Return BuhRoot.NewObject("ОписаниеТипов", TypeName).Типы().Получить(0)
    End Function
Требовать и эффективности, и гибкости от одной и той же программы — все равно, что искать очаровательную и скромную жену... по-видимому, нам следует остановиться на чем-то одном из двух. Фредерик Брукс-младший