На работе мы используем EFCore на нашем уровне данных и graphql-dotnet для управления запросами API, у меня проблема с обновлением некоторых наших больших объектов с использованием мутаций GraphQL.Когда пользователь отправляет частичное обновление модели, мы хотели бы обновить в нашей базе данных только те поля, которые фактически были изменены мутацией.Проблема, с которой мы сталкиваемся, заключается в том, что, поскольку мы напрямую сопоставляем входные данные с сущностью, когда какое-то поле было преднамеренно передано как нулевое, или поле вообще не было указано в мутации, мы получаем значение свойства как нулевое.Таким образом, мы не сможем отправить изменения в базу данных, в противном случае мы неверно обновим группу полей до нуля.
Итак, нам нужен способ определить, какие поля отправляются в мутации, и только обновлять их.В JS это достигается путем проверки, является ли значение свойства неопределенным, если значение равно null, мы знаем, что оно было преднамеренно передано как null.
Некоторые обходные пути, о которых мы думали, использовали отражение в словаре дляобновить только указанные поля.Но нам нужно было бы распространить отражение на каждую мутацию.Другое решение состояло в том, чтобы иметь свойство isChanged для каждого обнуляемого свойства в нашей модели и изменить их в указанном установщике свойств, но ... cmon ...
Ниже приведен некоторый код в качестве примера этой ситуации:
Класс человека:
public class Human
{
public Id { get; set; }
public string Name { get; set; }
public string HomePlanet { get; set; }
}
Тип GraphQL:
public class HumanType : ObjectGraphType<Human>
{
public HumanType()
{
Name = "Human";
Field(h => h.Id).Description("The id of the human.");
Field(h => h.Name, nullable: true).Description("The name of the human.");
Field(h => h.HomePlanet, nullable: true).Description("The home planet of the human.");
}
}
Тип ввода:
public class HumanInputType : InputObjectGraphType
{
public HumanInputType()
{
Name = "HumanInput";
Field<NonNullGraphType<StringGraphType>>("name");
//The problematic field
Field<StringGraphType>("homePlanet");
}
}
Мутация человека:
/// Example JSON request for an update mutation without HomePlanet
/// {
/// "query": "mutation ($human:HumanInput!){ createHuman(human: $human) { id name } }",
/// "variables": {
/// "human": {
/// "name": "Boba Fett"
/// }
/// }
/// }
///
public class StarWarsMutation : ObjectGraphType<object>
{
public StarWarsMutation(StarWarsRepository data)
{
Name = "Mutation";
Field<HumanType>(
"createOrUpdateHuman",
arguments: new QueryArguments(
new QueryArgument<NonNullGraphType<HumanInputType>> {Name = "human"}
),
resolve: context =>
{
//After conversion human.HomePlanet is null. But it was not informed, we should keep what is on the database at the moment
var human = context.GetArgument<Human>("human");
//On EFCore the Update method is equivalent to an InsertOrUpdate method
return data.Update(human);
});
}
}