Я пытаюсь создать приложение ASP. NET Core 3.1, используя Entity Framework Core и Hot Chocolate. Приложение должно поддерживать создание, запросы, обновление и удаление объектов через GraphQL. В некоторых полях должны быть значения.
Создание, запрос и удаление объектов не является проблемой, однако обновление объектов более сложно. Проблема, которую я пытаюсь решить, заключается в частичном обновлении.
Следующий объект модели используется Entity Framework для создания таблицы базы данных с помощью кода вначале.
public class Warehouse
{
[Key]
public int Id { get; set; }
[Required]
public string Code { get; set; }
public string CompanyName { get; set; }
[Required]
public string WarehouseName { get; set; }
public string Telephone { get; set; }
public string VATNumber { get; set; }
}
Я могу создать запись в базе данных с мутацией определила что-то вроде этого:
public class WarehouseMutation : ObjectType
{
protected override void Configure(IObjectTypeDescriptor descriptor)
{
descriptor.Field("create")
.Argument("input", a => a.Type<InputObjectType<Warehouse>>())
.Type<ObjectType<Warehouse>>()
.Resolver(async context =>
{
var input = context.Argument<Warehouse>("input");
var provider = context.Service<IWarehouseStore>();
return await provider.CreateWarehouse(input);
});
}
}
На данный момент объекты маленькие, но у них будет гораздо больше полей до завершения проекта. Мне нужно оставить возможность GraphQL отправлять данные только для тех полей, которые изменились, однако, если я использую тот же InputObjectType для обновлений, я сталкиваюсь с двумя проблемами.
- Обновление должно включать все "Обязательно" "fields.
- Обновление пытается установить для всех непредоставленных значений их значения по умолчанию.
Чтобы избежать этой проблемы, я рассмотрел предоставленный тип Optional<>
generi c от HotChocolate. Это требует определения нового типа «Обновление», например:
public class WarehouseUpdate
{
public int Id { get; set; } // Must always be specified
public Optional<string> Code { get; set; }
public Optional<string> CompanyName { get; set; }
public Optional<string> WarehouseName { get; set; }
public Optional<string> Telephone { get; set; }
public Optional<string> VATNumber { get; set; }
}
Добавление этого к мутации
descriptor.Field("update")
.Argument("input", a => a.Type<InputObjectType<WarehouseUpdate>>())
.Type<ObjectType<Warehouse>>()
.Resolver(async context =>
{
var input = context.Argument<WarehouseUpdate>("input");
var provider = context.Service<IWarehouseStore>();
return await provider.UpdateWarehouse(input);
});
Затем метод UpdateWarehouse должен обновить только те поля, которые были предоставлены значение.
public async Task<Warehouse> UpdateWarehouse(WarehouseUpdate input)
{
var item = await _context.Warehouses.FindAsync(input.Id);
if (item == null)
throw new KeyNotFoundException("No item exists with specified key");
if (input.Code.HasValue)
item.Code = input.Code;
if (input.WarehouseName.HasValue)
item.WarehouseName = input.WarehouseName;
if (input.CompanyName.HasValue)
item.CompanyName = input.CompanyName;
if (input.Telephone.HasValue)
item.Telephone = input.Telephone;
if (input.VATNumber.HasValue)
item.VATNumber = input.VATNumber;
await _context.SaveChangesAsync();
return item;
}
Хотя это работает, у него есть пара существенных недостатков.
- Поскольку Enity Framework не понимает типы
Optional<>
generi c, каждая модель потребует 2 класса - Метод обновления должен иметь условный код для каждого поля для обновления Это, очевидно, не идеально.
Entity Framework может использоваться вместе с классом JsonPatchDocument<>
generi c. Это позволяет применять частичные обновления к объекту, не требуя специального кода. Однако я изо всех сил пытаюсь найти способ объединить это с реализацией Hot Chocolate GraphQL.
Чтобы сделать эту работу, я пытаюсь создать собственный InputObjectType, который ведет себя так, как будто свойства определены с использованием Optional<>
и отображается на тип CLR JsonPatchDocument<>
. Это будет работать путем создания пользовательских сопоставлений для каждого свойства в классе модели с помощью отражения. Однако я обнаружил, что некоторые из свойств (IsOptional
), которые определяют способ обработки запроса средой, являются внутренними по отношению к платформе Hot Chocolate и недоступны из переопределяемых методов в пользовательском классе.
I Также рассмотрены способы
- Отображение свойств
Optional<>
UpdateClass в JsonPatchDocument<>
объект - Использование ткачества кода для генерации класса с
Optional<>
версиями каждого свойства - Переопределение кода EF в первую очередь для обработки
Optional<>
свойств
Я ищу любые идеи относительно того, как я могу реализовать это, используя обобщенный c подход и избегая необходимости писать 3 отдельных кодовых блока для каждого типа - которые должны быть синхронизированы c друг с другом.