c# - 当另一个属性更改时更新实体属性(实体初始化后)

标签 c# wpf entity-framework code-first

我在由 SQL CE 数据库支持的 WPF MVVM 应用程序中使用 Entity Framework 和代码优先方法。我正在尝试设计一个模型类,它可以简单地更新其一个属性值以响应其另一个属性值的更改。基本上,我正在寻找一种方法来定义在 EF 初始化实例后“ self 跟踪”的 poco。如果答案涉及放弃 Code First,那么也许这是唯一可行的途径(不确定)。一个基本示例:

class ThingModel
{
    public int Id { get; set; }

    public bool OutsideDbNeedsUpdate { get; set; }

    private string _foo;

    public string Foo
    {
        get { return _foo; }

        set
        {
            if (_foo != value)
            {
                _foo = value;

                OutsideDbNeedsUpdate = true;
            }
        }
    }
}

但是,上述问题是,每当 DbContext 在运行时初始化实例并设置字段时,我的类都会过早地设置依赖字段作为响应。换句话说,我正在寻找一种简单的模式,允许我的 poco 类仅在 EF 完成初始化实例上的字段后执行此特殊的更改跟踪。

我意识到我可以做类似解决方案 here 的事情 但我的业务案例要求这种特殊的更改跟踪与 EF 更改跟踪分离,换句话说,我需要具有 SaveChanges 的能力,无论上面的 HasChanges 属性的状态如何。这是因为我希望能够定期检查实体上的 HasChanges 属性,然后更新外部数据库中的相关值(与支持 EF DbContext 的数据库不同),并且 EF DB 之间可能会发生许多更改/保存推送到外部数据库。因此,我希望将标志与记录保留在我的数据库中,并在定期更新外部数据库时将其重置为 false。

最佳答案

编辑后我认为您可以使用 ObjectMaterialized event

This event is raised after all scalar, complex, and reference properties have been set on an object, but before collections are loaded.

将其放入 DbContext 的构造函数中:

((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized +=
    HandleObjectMaterialized;

方法:

private void HandleObjectMaterialized(object sender, ObjectMaterializedEventArgs e)
{ }

现在的问题是,方法体中应该放什么?也许最简单的解决方案是定义一个接口(interface)

interface IChangeTracker
{
    bool Materialized { get; set; }
    bool OutsideDbNeedsUpdate { get; }
}

并让你想要跟踪的类实现这个接口(interface)。

然后,在 HandleObjectMaterialized 中您可以执行以下操作:

var entity = e.Entity as IChangeTracker;
if (entity != null)
{
    entity.Materialized = true;
}

在此之后,您就知道何时可以在内部设置 OutsideDbNeedsUpdate


原文

一般来说,不建议使用带有副作用的属性(嗯,更准确地说,比改变所代表的状态有更多的副作用)。也许这条规则有异常(exception),但大多数时候,属性之间存在依赖关系并不是一个好主意。

我必须猜测一下你能做的最好的事情,因为我不知道你真正的代码是关于什么的,但也许可以将逻辑放在 setter/getter 中。只是一个例子:

public State State
{
   get { return this.EndDate.HasValue ? MyState.Completed : this._state; }
   set { this._state = value; }
}

这不会消除相互依赖性,但会将生效时间推迟到访问属性的时间。在您的情况下,这可能不会早于 SaveChanges()

另一种策略是创建一个同时设置两个属性的方法。方法预计会有副作用,尤其是当它们的名称明确表明它时。您可以使用类似 SetMasterAndDependent (string master) 的方法。

现在的方法在数据绑定(bind)场景中并不方便。在这种情况下,您最好让 View 模型设置这两个属性或调用上面的方法。

关于c# - 当另一个属性更改时更新实体属性(实体初始化后),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14363619/

相关文章:

c# - 在 ASP.NET Core Process 中创建的子进程在退出时被杀死

c# - 如何以编程方式自动将我的 c# 应用程序问题添加到 Github

wpf - 将复杂对象传递给子窗口

wpf - 如何以编程方式更改边框背景图像

c# - 在 MVVM 模式中使用 ASP.NET MVC 中的 C# 扩展方法

c# - 错误: The cast to value type 'System.Int32' failed because the materialized value is null

c# - 将资源分配给 CustomMessageBox.Content 时出现 ArgumentException

wpf - 如何让 ItemsSource 刷新其绑定(bind)?

asp.net - 如何提高ASP.NET MVC3应用程序数据查询性能?

c# - MVP、泛型和 DRY