По сути, я хочу знать, есть ли способ узнать, какие свойства объекта были установлены, чтобы я знал, какие свойства помечать как измененные для EFCore, и мой валидатор.
Скажем, например, у меня есть эти два класса:
class Foo
{
public int Id { get; set; }
public string Name { get; set; }
public string Content { get; set; }
public Bar TheBar { get; set; }
public ICollection<Bar> Bars { get; set; }
}
class Bar
{
public int Id { get; set; }
public string Name { get; set; }
}
Я также должен предположить, что нулевое значение или значение по умолчанию может быть допустимым значением для любого свойства. Это означает, что я не могу выполнить проверку, например if (prop.equals(default(PropType)))
, чтобы проверить, установлено ли свойство.
На данный момент у меня есть общий метод обновления, который выглядит следующим образом:
public ExecutionResult<TModel> ExecuteUpdate<TModel>(TModel model, params Expression<Func<TModel, object>>[] updatedProperties)
{
// Validation and EFCore calls
}
Используя этот метод, я могу сделать что-то вроде этого, что позволит мне вручную установить, какие свойства будут обновляться на основе конечной точки Http. то есть. конечная точка обновления пароля будет изменять только свойство пароля в модели, а не каждое свойство в модели:
var myFooOne = new Foo
{
Id = 1,
Name = "New Name",
Content = "Some new content"
}
// This allows me validate only the updated properties, and allow me to attatch the model to EFCore and only set the modified flag on the modified properties to create an optimal query
endPoint.ExecuteUpdate(myFooOne, foo => foo.Name, foo.Content);
Проблема с моим текущим решением заключается в том, что мне нужно проверить / обновить любое не примитивное свойство. Используя мое текущее решение, я должен был бы сделать что-то вроде этого:
// Only the Name property of the TheBar property was updated
var myFooTwo = new Foo
{
Id = 1,
TheBar = new Bar
{
// Id of a specific Bar already in the database
Id = 5,
Name = "New Name"
}
}
endPoint.ExecuteUpdate(myFooTwo, foo => foo.TheBar.Name);
С этим связаны две проблемы: с помощью селектора я могу получить только такую конкретную информацию, как сам прямой объект, поэтому я не могу сказать EFCore, какие свойства свойства TheBar
являются грязными, я могу только пометить все свойство объекта как грязное (что неэффективно). И во-вторых, такие селекторы Expression даже не будут работать с чем-то более сложным, чем выбор непосредственного свойства, т.е. foo.TheBar
нормально, но foo.TheBar.Name
выдает ArgumentException. Это становится более сложным с коллекциями и даже с вложенными объектами.
У меня есть идея обернуть все мои типы в обертку следующим образом:
enum WrapperStatus
{
Unknown,
NotSet,
Set
}
class Wrapper<T>
{
T Value { get; }
WrapperStatus Status { get; }
}
class FooEntity
{
Wrapper<int> Id { get; set; }
Wrapper<Bar> TheBar { get; set; }
// Same for rest of properties and all models
}
Тогда при проверке и обновлении я могу сделать что-то вроде этого:
var foo = new FooEntity
{
Id = new Wrapper<int>
{
Value = 1,
Status = WrapperStatus.Set
},
Name = new Wrapper<string>
{
Value = "New Name",
WrapperStatus.Set
}
}
По сути, моя идея состояла в том, чтобы создать обертку вокруг каждой модели, чтобы каждое свойство каждой модели было помечено флагом WrapperStatus
, и я мог бы добавить столько разных флагов, сколько необходимо: Updated, Null, UnChanged
и т. Д.
После того, как я проверил модель, что было бы легко сделать, потому что я знаю, какие свойства нужно проверять на основе флагов, я могу использовать адаптер для преобразования WrapperModel в реальную модель и передать его в EFCore, одновременно имея возможность легко установить флаг Modfied на необходимые свойства. Единственная причина, по которой я этого еще не сделал, заключается в том, что для этого по сути потребуется создание модели дважды: одна для модели EFCore и еще раз для модели оболочки. Теперь я могу упростить инициализацию оболочки, используя ключевое слово operator
и некоторые статические инициализаторы, но я хотел посмотреть, есть ли более простой способ.
Я знаю, что это много информации, но я могу уточнить все, что нужно.