C#如何知道已设置哪些属性来验证并标记EFCore修改后的标志

时间:2019-06-22 01:49:57

标签: c# validation object entity-framework-core

从本质上讲,我想知道是否有一种方法可以知道已设置对象的哪些属性,以便知道将哪些属性标记为针对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端点更新的属性。即。更新密码端点只会更改模型上的password属性,而不会更改模型上的每个属性:

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属性中的哪些特定属性是脏的,我只能将整个属性对象标记为脏(效率低下)。还有两个,像这样的表达式选择器甚至无​​法处理比选择立即属性即复杂的事情。 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,同时也能够轻松在所需属性上设置已修改标志。我尚未执行此操作的唯一原因是,它实际上需要对模型进行两次创建,一次用于EFCore模型,另一次用于包装模型。现在,我可以使包装器更容易使用operator关键字和一些静态初始值设定项进行初始化,但是我想先看看是否有一种更简单的方法。

我知道这是很多信息,但是我可以澄清所有需要的信息。

0 个答案:

没有答案
相关问题