OData сервис без написания кода

от автора

Одним из наиболее важных аспектов разработки программного обеспечения является быстрое создание прототипов. Для большинства служб необходимы по крайней мере некоторые операции CRUD, и большинство приложений можно описать как приложения, управляемые данными. API, которые я пишу, в основном берут данные из базы данных и возвращает их клиенту в виде JSON. OdataToEntity — это инструмент, который генерирует API из базы данных и устраняет необходимость в написании отдельного REST API.

В этой статье я покажу, как OdataToEntity может помочь устранить скучную работу по написанию CRUD методов. В прошлой статье я рассказывал как создать OData сервис с минимальным кодированием, в этой статье я покажу как сделать это вообще без написания кода.

Эта функциональность доступна в проекте OdataToEntity.EfCore.DynamicDataContext, который является частью библиотеки OdataToEntity. Реализован пример HTTP сервера в виде консольной программы, принимающей на вход строку подключения к базе данных. Поддерживаются базы данных: MySql, PostgreSql, Sql Server. Помимо таблиц и CRUD операций над ними, доступны представления, хранимые процедуры и функции.

Описание HTTP сервера

Исходный код сервера доступен на GitHub.
Настройка сервера осуществляется через файл конфигурации. Это стандартный файл Asp .net core в который добавлен ключ OdataToEntity

"OdataToEntity": {   "BasePath" :  "api",   "Provider": "sqlserver",   "ConnectionString": "Server=.\\sqlexpress;Initial Catalog=OdataToEntity;Trusted_Connection=Yes;",   "UseRelationalNulls": true,   "InformationSchemaMappingFileName": "InformationSchemaMapping.json" }

«BasePath» — базовый путь в URL сервера.
«Provider» — тип базы данных, возможные значения mysql, postgresql, sqlserver.
«ConnectionString» — строка подключения к базе данных.
«UseRelationalNulls» — указывает, следует ли использовать семантику реляционной базы данных
при сравнении нулевых значений.
«InformationSchemaMappingFileName» — дополнительная настройка отображения базы данных в API.

Программа автоматически обнаруживает процедуры, функции, отношения между таблицами базы данных, проверяя их внешние ключи. Я использую это для встраивания отношений в схему OData сервиса. Для дополнительной настройки имен используется файл InformationSchemaMapping.json это сериализованный класс InformationSchemaMapping.
Ключ «Operations» описывает хранимые процедуры и функции, «Tables» — таблицы и представления. Свойства «DbName» — имя в базе, «EdmName» — имя в сервисе, «Exclude» исключает объект базы и сервиса. Если хранимая процедура/функция возвращает таблицу, то имя таблицы надо задать в свойстве «ResultTableDbName». Для изменения имени навигационного свойства нужно использовать ключ «Navigations», где свойство «TargetTableName» указывает на целевую таблицу навигационного свойства, а «NavigationName» — его имя. Если таблица содержит несколько внешних ключей на одну и туже таблицу, то для различения этих навигационных свойств вместо «TargetTableName» необходимо задать «ConstraintName» — имя внешнего ключа базы данных. Для свойства многие-ко-многим нужно задать «ManyToManyTarget» — имя целевой таблицы ( дополнительную информацию о реализации многие-ко-многим смотрите по этой ссылке ).

Пример кода

Если вам необходимо использовать этот функционал в своем коде, добавьте ссылку на проект OdataToEntity.EfCore.DynamicDataContext

//Load our schema mappings (optional) InformationSchemaMapping informationSchemaMapping = GetMappings();  //create database schema var optionsFactory = new DynamicSchemaFactory("sqlserver", @"Server=.\sqlexpress;Initial Catalog=OdataToEntity;Trusted_Connection=Yes;"); ProviderSpecificSchema providerSchema = optionsFactory.CreateSchema(useRelationalNulls: true);  IEdmModel dynamicEdmModel; //create database information_schema provider using (var metadataProvider = providerSchema.CreateMetadataProvider(informationSchemaMapping)) {     //create ef entity types manager     DynamicTypeDefinitionManager typeDefinitionManager = DynamicTypeDefinitionManager.Create(metadataProvider);     //Create adapter data access     var dataAdapter = new DynamicDataAdapter(typeDefinitionManager);     //Build OData edm model     dynamicEdmModel = dataAdapter.BuildEdmModel(metadataProvider); }  //Create query parser var parser = new OeParser(new Uri("http://dummy"), dynamicEdmModel); //Query var uri = new Uri("http://dummy/Orders?$expand=Customer,Items&$orderby=Id"); //The result of the query var stream = new MemoryStream(); //Execute query await parser.ExecuteGetAsync(uri, OeRequestHeaders.JsonDefault, stream, CancellationToken.None); stream.Position = 0; //Get result as string Console.WriteLine(new StreamReader(stream).ReadToEnd());

Как это работает

По представлениям information_schema строится контекст Entity Framework. Сущности контекста являются наследниками абстрактного класса DynamicType. Этот класс накладывает ограничения на общее количество столбцов в таблице, их не должно быть больше 50. Количество навигационных свойств не должно превышать для свойств со стороны первичного ключа 50, со стороны внешнего ключа 30.

Общее количество таблиц и представлений ограничено 110, это количество ограничено реализациями класса DynamicType. Вы можете увеличить количество свойств или классов, добавив их в исходный код.
По контексту Entity Framework строится схема OData, как уже было описано в в моей предыдущей статье. Эта схема необходима для трансляции запроса в дерево выражений (expression tree), которое передается в контекст EntityFramework.

Структура исходного кода

Солюшен — sln\OdataToEntity.Test.DynamicDataContext.sln
Проект — source\OdataToEntity.EfCore.DynamicDataContext
HTTP сервер — test\OdataToEntity.Test.DynamicDataContext.AspServer
Тесты — OdataToEntity.Test.DynamicDataContext
Sql скрипты тестовой базы — test\sql_scripts


ссылка на оригинал статьи https://habr.com/ru/post/459656/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *