Минимальные требования

  • Технологическая платформа 1С версии 8.x
  • Возможность COM-соединения к информационной базе 1С
  • Microsoft .Net Framework версии 4.0 или выше

Загрузка

Самый простой способ начать использовать библиотеку Vanessa Sharp это загрузить ее c NuGet Gallery через диалог (инструкция здесь) введя для поиска код библиотеки: VanessaSharp. Или же используя NuGet Package Manager (инструкция использования здесь) запустив команду:

PM> Install-Package VanessaSharp

Также можно получить NuGet-пакет библиотеки (для собственной NuGet-галереи) или zip-архив с dll-файлами библиотеки на странице "Скачать".

Примеры использования

Для того чтобы работать с примерами необходимо выполнить минимальные требования, описанные выше. Желательно, но необязательно иметь при себе конфигурацию 1С поставляемую с учебной версией технологической платформы 1C. Так как для нас важно понять, как работать с данными 1С используя Vanessa Sharp, то на пользовательском интерфейсе не будем акцентировать внимание и выберем простой вариант консольного приложения. Примеры с использованием Vanessa Sharp будем писать на языке C#. Для этого вначале создадим проект C# консольного приложения. Как было описано в разделе Загрузка, подключим библиотеки Vanessa Sharp используя диалог NuGet, введя кодовое название VanessaSharp для поиска библиотеки в NuGet галлереи.

После успешного подключения библиотеки можно приступить к написанию примеров.

Проект обсуждаемых ниже примеров можно скачать здесь

Пример использования ADO.Net провайдера 1С

Первым делом разберем, как можно использовать 1С ADO.Net провайдер Vanessa Sharp для выполнения запроса к информационной базе 1С и получения данных. Для успешной работы необходимо знание встроенного языка запросов 1С (похожего на SQL) и навыков работы с ADO.Net. Кроме этого, каких-то дополнительных знаний не требуется. Напомним, что работа для получения данных из источника данных через ADO.Net состоит из следующих шагов:

  1. Создание объекта соединения с заданием строки подключения к источнику данных.
  2. Создание объекта команды запроса на получение данных из источника данных. Как правило, текстом команды является какой-нибудь диалект SQL.
  3. Открытие соединения.
  4. Выполнение команды запроса данных из источника с получением объекта читателя данных. Как правило, читатель данных представляет из себя курсор, который позволяет последовательно проходить по возвращаемым из источника записям данных.
  5. Итеративное чтение данных из возвращенных записей с помощью читателя данных.
  6. Закрытие читателя данных.
  7. Закрытие соединения.

Разберем по пунктам как работать с 1С ADO.Net провайдером Vanessa Sharp.

Создание объекта соединения с заданием строки подключения к источнику данных

Для создания объекта соединения Vanessa Sharp необходимо создать экземпляр класса OneSConnection, передав в конструктор строку подключения или задав строку подключения через свойство ConnectionString. Как же должна выглядеть строка подключения?

Так как Vanessa Sharp работает через COM-соединение, то для того, чтобы ADO.Net провайдер Vanessa Sharp работал требуется возможность подключения к информационной базе 1С через COM-соединение. Как известно для открытия COM-соединения необходимо коннектору передать строку подключения. Строка подключения выглядит примерно так: File="Путь к каталогу в которой находится файл информационной базы 1С";Usr="Имя пользователя, под которым производится подключение";Pwd="Пароль пользователя, под которым производится подключение". Хорошая новость заключается в том, что для подключения к 1С через 1C ADO.Net провайдер Vanessa Sharp используется та же строка подключения, что и при прямом подключении через COM-соединение. В ADO.Net строку подключения можно сконструировать, используя объект построителя строки подключения. В Vanessa Sharp для этого используется класс OneSConnectionStringBuilder. Задать путь к каталогу информационной базы 1С можно задав значение свойства Catalog экземпляра OneSConnectionStringBuilder:

                        // Формирование строки подключения с использованием построителя:
                        var connectionStringBuilder = new OneSConnectionStringBuilder
                        {
                            Catalog = ONES_INFO_DB_PATH,
                            User = USER_NAME,
                            Password = USER_PASSWORD
                        };

                        Console.WriteLine(
                            "Строка подключения к информационной БД: {0}",
                            connectionStringBuilder.ConnectionString);

                        // Создание подключения:
                        using (var connection = new OneSConnection(connectionStringBuilder.ConnectionString))
                        {
                            // Здесь код обсуждаемый ниже, в котором используется переменная connection
                        }

Перед открытием можно задать параметры коннектора 1С такие как PoolTimeout, PoolCapacity. Для этого надо задать значения одноименных свойств экземпляра OneSConnection.

Создание объекта команды запроса на получение данных из источника данных

В Vanessa Sharp экземпляры класса OneSCommand являются объектами команды. В свойстве CommandText объекта команды задается запрос на встроенном языке запросов 1С (не считая официальной документации, подробнее о данном языке можно почитать здесь). Если запрос параметрический, то необходимо также в объект команды добавить параметры запроса по имени с заданными значениями. Допустим в конфигурации информационной базы 1С с которой мы работаем есть документ «ЗаказНаПроизводство» с реквизитами «Старт», «Финиш», «Количество» и «Комментарий». Тогда для получения данных можно выполнить следующий параметрический запрос к информационной базе 1С:


                            ВЫБРАТЬ Старт, Финиш, Количество, Комментарий
                            ИЗ Документ.ЗаказНаПроизводство 
                            ГДЕ Количество > &Минимум
                            УПОРЯДОЧИТЬ ПО Старт УБЫВ
                        
где «Минимум» имя параметра. Для создания объекта команды соответствующего данному запросу надо написать:
                            
                            // Создание объекта запроса:
                            const string SQL = "ВЫБРАТЬ Старт, Финиш, Количество, Комментарий ИЗ Документ.ЗаказНаПроизводство ГДЕ Количество > &Минимум УПОРЯДОЧИТЬ ПО Старт УБЫВ";
                            using (var command = new OneSCommand(connection, SQL))
                            {
                                // Добавление значения параметра:
                                command.Parameters.Add("Минимум", 10);
                            
                                // Здесь код обсуждаемый ниже, в котором используется переменная command
                            }

Открытие соединения

Осуществляется вызовом метода Open у объекта соединения:


                            // Перед выполнением запроса необходимо обязательно открыть соединение:
                            connection.Open();
                            

Выполнение команды запроса данных из источника с получением объекта читателя данных


                        // Выполнение запроса и получение результатов:
                        using (var reader = command.ExecuteReader())
                        {
                            // Здесь код обсуждаемый ниже, в котором используется переменная reader
                        }
При этом возвращается экземпляр класса OneSDataReader, являющейся объектом читателем данных, возвращаемых в результате выполнения запроса к источнику данных.

Итеративное чтение данных из возвращенных записей с помощью читателя данных

Чтение очередной записи производится вызовом метода Read у объекта читателя данных. В случае, если существует следующая запись в результате запроса, то метод возвращает true, в случае же когда записей в результате больше нет, то возвращается false. Для чтения значений полей можно использовать как методы нетипизированного доступа такие как GetValue, или же методы получения строго типизированных значений такие как GetString, GetInt32, GetDateTime и т.д. В отличии от других провайдеров данных (таких как MS SQL) нет особой разницы в производительности за счет отсутствия упаковки при работе c Vanessa Sharp, так как Vanessa Sharp работает через COM-соединение, с использованием технологии позднего связывания ([OLE] Automation), которое всегда возвращает упакованные значения. Несмотря на это, все равно рекомендуется для примитивных типов пользоваться методами типизированного доступа, так как вам не придется самим делать необходимую конвертацию. Итак, для чтения данных результата запроса и их печати можно написать следующий код:

                        while (reader.Read())
                        {
                            var start = reader.GetDateTime(0);
                            var end = reader.GetDateTime(1);
                            var quantity = reader.GetInt32(2);
                            var comment = reader.GetString(3);

                            Console.WriteLine("{0}\t{1}\t{2}\t{3}", start, end, quantity, comment);
                        }

Закрытие читателя данных

Закрыть читатель можно вызвав метод Close или же Dispose.

Закрытие соединения

Закрыть соединение можно вызвав метод Close или же Dispose. В C# как правило для этого используют синтаксическую конструкцию using.

Пример использования LinqTo1C

Как известно основная идея LINQ это формирование запроса к источнику данных средствами языка общего использования, таких как C# и VB.Net. При этом производится необходимая проверка типов и наличие членов у типов, что невозможно сделать при формировании запроса, как строки символов. В результате компилятор языка поддерживающего LINQ вместо строки символов строит абстрактное синтаксическое дерево (AST) выражения запроса, которое передается так называемому LINQ-провайдеру источника данных, который интерпретирует AST определенным образом в зависимости от типа источника данных. Более подробнее про LINQ, можно почитать в любом авторитетном пособии по C# 3.0 или выше. Для тех же, кто боится толстых книжек, рекомендуется карманный справочник по LINQ.

Для того чтобы выполнять запросы с помощью LinqTo1C, входящей в Vanessa Sharp необходимо создать экземпляр класса OneSDataContext. При создании экземпляра в конструктор можно передать объект соединения типа OneSConnection с заданными свойствами, необходимыми для открытия соединения:

            // Создание контекста данных через создание и настройку подключения:
            using (var connection = new OneSConnection(ConnectionString))
            {
                // Дополнительно настраиваем подключение:
                connection.PoolTimeout = 1000;
                connection.PoolCapacity = 10;

                // Создание контекста данных:
                using (var dataContext = new OneSDataContext(connection))
                {
                   // Код обсуждаемый ниже, в котором используется переменная dataContext
                }
            }

Или же можно просто передать строку подключения в конструктор OneSDataContext, которую необходимо задать для соединения с информационной базой 1С:

            // Создание контекста данных используя строку подключения к информационной базе 1С:
            using (var dataContext = new OneSDataContext(ConnectionString))
            {
               // Код обсуждаемый ниже, в котором используется переменная dataContext   
            }
Как формировать строку подключения объяснялось выше в примере про использование ADO.Net.

LinqTo1C поддерживает несколько вариантов написания запроса статический и динамический. Возможно, в будущем появится третий вариант - гибридный. Начнем со статического варианта.

Пример использования статического LinqTo1C

Статический вариант подразумевает, что в LINQ-запросе используется какой-то специальный тип, который ассоциируется с каким-либо прикладным объектом конфигурации 1С (справочником, документом, регистром и т.д.). Если точнее говорить, даже не с объектом, а табличным видом данных прикладного объекта возвращаемого запросами написанных на встроенном языке запросов 1С. Ассоциируемый тип для прикладного объекта желательно делать кортежем без логики (только поля или автосвойства), для того чтобы избежать сторонних эффектов. Например, для ассоциации с документом «ЗаказНаПроизводство» создадим класс (можно и структуру) ProductionOrder, следующим образом:

            public sealed class ProductionOrder
            {
                 public object OperationType;

                 public OneSValue Company;

                 public DateTime Start;

                 public DateTime End;

                 public int Quantity { get; set; }

                 public string Comment { get; set; }
            }
Причем для ассоциации с реквизитами прикладного объекта необходимо использовать публичные поля или же свойства, которые имеют публичные аксессоры, как на чтение, так и на запись.

Создание типа не достаточно, для того чтобы его использовать в LINQ-запросах. Необходимо задать соответствие между типом CLR и прикладными объектом 1С, между членами типа CLR и реквизитами прикладного объекта 1С. Если спектр методов для задания соответствий, но на данный момент в LinqTo1C соответствия задаются только с помощью атрибутов в CompileTime. В дальнейшем планируется поддержать задание соответствий с помощью fluent-интерфейса в RunTime. Итак для того, чтобы задать соответствие между типом CLR и прикладным объектом 1С надо воспользоваться атрибутом OneSDataSourceAttribute. А для того чтобы задать соответствие между членами типа CLR и реквизитами прикладного объекта 1С нужно воспользоваться атрибутом OneSDataColumnAttribute. В соответствии с вышесказанным промаркируем тип ProductionOrder:

        [OneSDataSource("Документ.ЗаказНаПроизводство")]
        public sealed class ProductionOrder
        {
            [OneSDataColumn("ВидОперации")]
            public object OperationType;

            [OneSDataColumn("Организация")]
            public OneSValue Company;

            [OneSDataColumn("Старт")]
            public DateTime Start;

            // Для привязки можно использовать публичные поля
            [OneSDataColumn("Финиш")]
            public DateTime End;

            // А можно использовать свойства с публичными аксессорами
            [OneSDataColumn("Количество")]
            public int Quantity { get; set; }

            [OneSDataColumn("Комментарий")]
            public string Comment { get; set; }
        }

Теперь мы можем написать LINQ-запрос с использованием типа ProductionOrder. Для это надо вызвать метод Get<ProductionOrder> у экземпляра класса OneSDataContext. Данный метод возвращает объект типа IQueryable<ProductionOrder>, над которым можно вызывать стандартные query-методы (правда не все они пока поддерживаются в LinqTo1C :( ). Например можно написать следующий linq-запрос:

                // Создание запроса получения данных из последовательности типизированных кортежей:
                var query = from o in dataContext.Get<ProductionOrder>()
                            where o.Quantity > MINIMUM
                            orderby o.Start descending
                            select new {o.Start, o.End, o.Quantity, o.Comment};
Соответствующий следующему запросу на встроенном языке запросов 1С:

                            ВЫБРАТЬ Старт, Финиш, Количество, Комментарий
                            ИЗ Документ.ЗаказНаПроизводство 
                            ГДЕ Количество > &Минимум
                            УПОРЯДОЧИТЬ ПО Старт УБЫВ
                        

После формирования запроса можно распечатать данные итеративно вычитывая из 1С кортежи анонимного типа следующим образом:

                // Печать результата:
                foreach (var tuple in query)
                {
                    Console.WriteLine("{0}\t{1}\t{2}\t{3}", tuple.Start, tuple.End, tuple.Quantity, tuple.Comment);
                }

Пример использования динамического LinqTo1C

Статический вариант подразумевает, что вся информация о реквизитах прикладного объекта известна на момент компиляции, что позволяет создать тип CLR, соответствующий прикладному объекту 1С и использовать его в LINQ-запросе. Ну что же делать, если это не так? В этом случае можно воспользоваться общим типом OneSDataRecord, ассоциируемый с любым источником данных 1С используемом в запросе на встроенном языке запросов 1С. К значениям полей экземпляра OneSDataRecord можно получить доступ на чтения воспользовавшись нетипизированными методами GetValue, или же методами типизированного доступа GetInt32, GetString и им подобным. Для того, чтобы создать linq-запрос с использованием OneSDataRecord надо у экземпляра класса OneSDataContext вызвать метод GetRecords, передав названия источника данных 1С.

Например, запрос, эквивалентный запросу встроенного языка 1С:


                            ВЫБРАТЬ Старт, Финиш, Количество, Комментарий
                            ИЗ Документ.ЗаказНаПроизводство 
                            ГДЕ Количество > &Минимум
                            УПОРЯДОЧИТЬ ПО Старт УБЫВ
                        
можно написать так:
                    // Создание запроса:
                    var query = from o in dataContext.GetRecords("Документ.ЗаказНаПроизводство")
                                where o.GetInt32("Количество") > MINIMUM
                                orderby o.GetDateTime("Старт") descending
                                select new
                                    {
                                        Start = o.GetDateTime("Старт"),
                                        End = o.GetDateTime("Финиш"),
                                        Quantity = o.GetInt32("Количество"),
                                        Comment = o.GetString("Комментарий")
                                    };