Как стать автором
Обновить

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

Время на прочтение4 мин
Количество просмотров7K

Одним из наиболее важных аспектов разработки программного обеспечения является быстрое создание прототипов. Для большинства служб необходимы по крайней мере некоторые операции 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();

//Configure context
var optionsBuilder = new DbContextOptionsBuilder<DynamicDbContext>();
optionsBuilder = optionsBuilder.UseSqlServer("Server=.\\sqlexpress;Initial Catalog=OdataToEntity;Trusted_Connection=Yes;");

IEdmModel dynamicEdmModel;
//create database schema
using (ProviderSpecificSchema providerSchema = new SqlServerSchema(optionsBuilder.Options))
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());

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


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

Теги:
Хабы:
Всего голосов 15: ↑12 и ↓3+9
Комментарии3

Публикации

Истории

Работа

.NET разработчик
70 вакансий

Ближайшие события