gifts2017

Linq to ODATA

Опубликовал Сергей Смирнов (Serginio) в раздел Обмен - Обмен с другими системами

1С сейчас совершенствует REST интерфейс приложения, автоматически генерируемый платформой, и протокол обмена ODATA версии 3. С недавнего времени появилась возможность обмениваться, используя JSON. На просторах интернета мало информации по использованию Linq для ODATA для 1С. Поэтому решил поделиться опытом. Это продолжение статей https://infostart.ru/public/402433/

ODATA это открытый веб-протокол для запроса и обновления данных. Он позволяет оперировать данными, используя в качестве запросов HTTP-команды.

 

http://v8.1c.ru/o7/201312rest/

Есть поддержка JSON

http://v8.1c.ru/o7/201410json/index.htm

 

Хорошая статья по публикации находится здесь

http://infostart.ru/public/305854/index.php?back&vote_id=245&rate=1&ID=305854%3Frate%3D1&bxajaxid=2da474348dcf168272d247336e249b99 

Для того, что бы редактировать состав  стандартного интерфейса можно воспользоваться обработкой

https://infostart.ru/public/297325/

Или программно установить используя метод УстановитьСоставСтандартногоИнтерфейсаOData

Массив = Новый Массив();

Для Каждого
Справочник Из Метаданные.Справочники Цикл
   
Массив.Добавить(Справочник);
КонецЦикла;

УстановитьСоставСтандартногоИнтерфейсаOData(Массив);

 

Затем в VS Добавить ссылку на службу используя URI

http://{АдресВебСервера}/{ИмяПубликации}/odata/standard.odata/$metadata

Получаем описание классов доступ и доступ к ODATA например так

var uriString = @"http://localhost/LinqBD/odata/standard.odata/";

            var context = new ServiceReference1.EnterpriseV8(new Uri(uriString));

 

            context.Format.UseJson();

            var query = context.CreateQuery<ServiceReference1.Catalog_Тестовый>(@"Catalog_Тестовый")

 

если не использовать context.Format.UseJson() то данные будут присылаться в формате XML

Можно получить один элемент по ключу

var query = context.CreateQuery<ServiceReference1.Catalog_Тестовый>(@"Catalog_Тестовый(guid'aada18ad-5308-11e5-8e05-c86000c70663')");

Можно добавлять фильтры например

 

var query = context.CreateQuery<ServiceReference1.Catalog_Тестовый>(@"Catalog_Тестовый")

                         .AddQueryOption("$filter", "Число le 100");

 

Но проще использовать доступ к ODATA через Linq. Например

 

var result = (from Тестовый in context.Catalog_Тестовый

                          where Тестовый.Число < 500

                          select Тестовый).ToList();

 

var result = (from Тестовый in context.Catalog_Тестовый

                          where Тестовый.Ref_Key == new Guid("aada18ad-5308-11e5-8e05-c86000c70663")

                          select Тестовый).SingleOrDefault();

 

То есть можно работать с ODATA полностью на Linq

 Подгрузка ссылочных реквизитов

https://msdn.microsoft.com/ru-ru/library/cc646508(v=vs.110).aspx

var ПустаяСсылка = new Guid("00000000 - 0000 - 0000 - 0000 - 000000000000");

 

            string НоменклатураНаименование = "";

            if (result.РеквизитСправочник_Key != ПустаяСсылка)

            {

                context.LoadProperty(result, "РеквизитСправочник");

 

               НоменклатураНаименование = result.РеквизитСправочник.Description;

            }

 

Для Неопределенных типов Можно создать функцию

object ПолучитьНеопределенныйТип(ServiceReference1.EnterpriseV8 context, string значение, string Тип)

        {

            switch (Тип)

            {

                case "StandardODATA.Undefined":

                    return null;

                case "StandardODATA.Catalog_Номенклатура": return context.Catalog_Номенклатура.Where(Тестовый => Тестовый.Ref_Key == new Guid(значение)).SingleOrDefault();

                case "Edm.Double": return Double.Parse(значение, System.Globalization.CultureInfo.InvariantCulture);

…..

            }

            return null;

        }

 

Ииспользовать

  dynamic    ЛюбаяССылка = ПолучитьНеопределенныйТип(context, result.ЛюбаяСсылка, result.ЛюбаяСсылка_Type);

     dynamic НеСсылочный = ПолучитьНеопределенныйТип(context, result.НеопределенныйНеССылочный, result.НеопределенныйНеССылочный_Type);

 

 По сути некая замена COM.

 

Полезные ссылки для запросов ODATA

https://msdn.microsoft.com/ru-ru/library/vstudio/dd673933(v=vs.100).aspx

 

Обновление, добавление и удаление записей

 https://msdn.microsoft.com/ru-ru/library/vstudio/dd756361(v=vs.100).aspx

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Олег Дмитров (baracuda) 06.10.15 14:32
Глоток свежего воздуха при изучении C# Odata.
2. Сергей Смирнов (Serginio) 06.10.15 16:53
3. Игорь Богданов (avz_1C) 29.02.16 14:18
Коллега, Вы продолжаете удивлять.
Спасибо.
Сегодня, как раз, возникла потребность разбирать метаданные нескольких
конфигураций, взаимодействием которых управляет модуль, созданный на C#.
Не успел подумать о Linq, как Вы подтвердили, своей публикацией, мои догадки.
4. Сергей Смирнов (Serginio) 29.02.16 17:41
Спасибо. Рад, что мои труды не пропадают зря
5. Артём Артёмов (TeMochkiN) 20.09.16 10:58
Здравствуйте!
Помогите, пожалуйста, пытаюсь добавить ссылку на службу в VS, а она постоянно запрашивает учетные данные и не дает её добавить:

Я ввожу имя пользователя, жму ОК, и снова появляется это же окно ввода имени пользователя и пароля.

После нескольких попыток, жму отмена и пишет следующее:



Я пробовал открыть данную ссылку в хроме он тоже запрашивает имя пользователя и пароль, я ввожу имя пользователя и всё загружается:


А вот Internet Explorer тоже не дает открыть эту ссылку. В чем может быть дело? IIS неправильно настроен?
6. Сергей Смирнов (Serginio) 20.09.16 11:10
Логин и пароль должны быть на латинице
7. Сергей Смирнов (Serginio) 25.10.16 14:21
Добавлю, что для Регистров бухгалтерии можно использовать функции для виртуальных таблиц.
<EntityContainer Name="EnterpriseV8" m:IsDefaultEntityContainer="true">
<EntitySet Name="AccountingRegister_Хозрасчетный" EntityType="StandardODATA.AccountingRegister_Хозрасчетный" />
<EntitySet Name="AccountingRegister_Хозрасчетный_RecordType" EntityType="StandardODATA.AccountingRegister_Хозрасчетный_RecordType" />
<FunctionImport Name="Balance" IsBindable="true" IsSideEffecting="false" ReturnType="Collection(StandardODATA.AccountingRegister_Хозрасчетный_Balance)">
<Parameter Name="bindingParameter" Type="StandardODATA.AccountingRegister_Хозрасчетный" />
<Parameter Name="AccountCondition" Type="Edm.String" />
<Parameter Name="Condition" Type="Edm.String" />
<Parameter Name="Dimensions" Type="Edm.String" />
<Parameter Name="ExtraDimensions" Type="Edm.String" />
<Parameter Name="Period" Type="Edm.DateTime" />
</FunctionImport>
<FunctionImport Name="Turnovers" IsBindable="true" IsSideEffecting="false" ReturnType="Collection(StandardODATA.AccountingRegister_Хозрасчетный_Turnover)">
<Parameter Name="bindingParameter" Type="StandardODATA.AccountingRegister_Хозрасчетный" />
<Parameter Name="AccountCondition" Type="Edm.String" />
<Parameter Name="BalancedAccountCondition" Type="Edm.String" />
<Parameter Name="BalancedExtraDimensions" Type="Edm.String" />
<Parameter Name="Condition" Type="Edm.String" />
<Parameter Name="Dimensions" Type="Edm.String" />
<Parameter Name="EndPeriod" Type="Edm.DateTime" />
<Parameter Name="ExtraDimensions" Type="Edm.String" />
<Parameter Name="StartPeriod" Type="Edm.DateTime" />
</FunctionImport>
<FunctionImport Name="BalanceAndTurnovers" IsBindable="true" IsSideEffecting="false" ReturnType="Collection(StandardODATA.AccountingRegister_Хозрасчетный_BalanceAndTurnover)">
<Parameter Name="bindingParameter" Type="StandardODATA.AccountingRegister_Хозрасчетный" />
<Parameter Name="Condition" Type="Edm.String" />
<Parameter Name="Dimensions" Type="Edm.String" />
<Parameter Name="EndPeriod" Type="Edm.DateTime" />
<Parameter Name="StartPeriod" Type="Edm.DateTime" />
</FunctionImport>
<FunctionImport Name="ExtDimensions" IsBindable="true" IsSideEffecting="false" ReturnType="Collection(StandardODATA.AccountingRegister_Хозрасчетный_ExtDimensions)">
<Parameter Name="bindingParameter" Type="StandardODATA.AccountingRegister_Хозрасчетный" />
</FunctionImport>
<FunctionImport Name="RecordsWithExtDimensions" IsBindable="true" IsSideEffecting="false" ReturnType="Collection(StandardODATA.AccountingRegister_Хозрасчетный_RecordsWithExtDimensions)">
<Parameter Name="bindingParameter" Type="StandardODATA.AccountingRegister_Хозрасчетный" />
<Parameter Name="Condition" Type="Edm.String" />
<Parameter Name="EndPeriod" Type="Edm.DateTime" />
<Parameter Name="Order" Type="Edm.String" />
<Parameter Name="StartPeriod" Type="Edm.DateTime" />
<Parameter Name="Top" Type="Edm.Int64" />
</FunctionImport>
<FunctionImport Name="DrCrTurnovers" IsBindable="true" IsSideEffecting="false" ReturnType="Collection(StandardODATA.AccountingRegister_Хозрасчетный_DrCrTurnover)">
<Parameter Name="bindingParameter" Type="StandardODATA.AccountingRegister_Хозрасчетный" />
<Parameter Name="AccountCondition" Type="Edm.String" />
<Parameter Name="BalancedAccountCondition" Type="Edm.String" />
<Parameter Name="BalancedExtraDimensions" Type="Edm.String" />
<Parameter Name="Condition" Type="Edm.String" />
<Parameter Name="Dimensions" Type="Edm.String" />
<Parameter Name="EndPeriod" Type="Edm.DateTime" />
<Parameter Name="ExtraDimensions" Type="Edm.String" />
<Parameter Name="StartPeriod" Type="Edm.DateTime" />
</FunctionImport>
</EntityContainer>
</Schema>
8. Сергей Смирнов (Serginio) 25.10.16 14:27
К сожалению VS их не подгружает. Но можно использовать CreateQuery. Но есть нюансы. Если сделать такой запрос

var query3 = context.CreateQuery<StandardODATA.AccountingRegister_Хозрасчетный_Turnover>(@"AccountingRegister_Хозрасчетный/Turnovers").ToList();


То 1С вернет такй тип

{

"odata.metadata": "http://localhost/DemoAccounting/odata/standard.odata/$metadata#Collection(StandardODATA.AccountingRegister_Хозрасчетный_Turnover)";,

"value": [


Для того, что бы программа поняла ответ нужно сделать такой запрос и программа не может привести Collection(StandardODATA.AccountingRegister_Хозрасчетный_Turnover)" к AccountingRegister_Хозрасчетный_Turnover

Поэтому создадим такой запрос

var query3 = context.CreateQuery<List<StandardODATA.AccountingRegister_Хозрасчетный_Turnover>>(@"AccountingRegister_Хозрасчетный/Turnovers").ToList();


То возвращается тип

query3 Count = 1 System.Collections.Generic.List<System.Collections.Generic.List<StandardODATA.AccountingRegister_Хозрасчетный_Turnover>>

Где вся коллекция лежит в первом элементе query3.Items[0]