我在由SQL CE数据库支持的WPF MVVM应用程序中使用Entity Framework和Code First方法。我正在尝试设计一个模型类,它可以简单地更新其中一个属性值,以响应其中一个属性值的变化。基本上,我正在寻找一种方法来定义在EF初始化实例后“自我跟踪”的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变更跟踪分离,换句话说,无论上面的HasChanges属性如何,我都需要具有SaveChanges的能力。这是因为我希望能够定期检查我的实体上的HasChanges属性,然后更新外部数据库中的相关值(不是支持EF DbContext的相同值),并且可能会在EF DB之间发生许多更改/保存推到外面的DB。因此,我希望在我的数据库中保留带有记录的标志,并在定期更新外部数据库时将其重置为false。
答案 0 :(得分:2)
编辑后,我认为您可以使用ObjectMaterialized event。
在对象上设置了所有标量,复杂和引用属性之后,但在加载集合之前,会引发此事件。
将它放在DbContext
:
((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized +=
HandleObjectMaterialized;
方法:
private void HandleObjectMaterialized(object sender, ObjectMaterializedEventArgs e)
{ }
现在问题是,在方法体中放什么?可能最简单的解决方案是定义一个接口
interface IChangeTracker
{
bool Materialized { get; set; }
bool OutsideDbNeedsUpdate { get; }
}
让你想要跟踪的类实现这个接口。
然后,在HandleObjectMaterialized
你可以做到:
var entity = e.Entity as IChangeTracker;
if (entity != null)
{
entity.Materialized = true;
}
在此之后,您知道何时可以在内部设置OutsideDbNeedsUpdate
。
原始文字
通常不推荐使用具有副作用的属性(更确切地说,具有比改变表示状态更多的副作用)。也许这个规则有例外,但大多数情况下,在属性之间存在依赖关系并不是一个好主意。
我必须猜测一下你能做得最好的一点,因为我不知道你真正的代码是什么,但是可能把逻辑放在getter中。举个例子:
public State State
{
get { return this.EndDate.HasValue ? MyState.Completed : this._state; }
set { this._state = value; }
}
这不会消除相互依赖关系,但它会将影响时刻推迟到访问属性的时间。在您的情况下,这可能不早于SaveChanges()
。
另一个策略是制作一个同时设置两个属性的方法。预计方法会产生副作用,特别是当它们的名称清楚地表明它时。您可以使用SetMasterAndDependent (string master)
等方法。
现在方法在数据绑定方案中不方便。在这种情况下,您最好让视图模型设置两个属性或调用上面的方法。