当我感觉它应该非常简单时,我真的很难让它发挥作用。
我已向服务层添加了一个缓存,用于存储从 EF 返回的数据。
当实体从 EF 返回并更新时,它的状态为EntityState.Modified
。
当它从缓存返回时,它的状态是EntityState.Detached
,这都是有意义的。
DbContext.Update
如果实体是,我会调用Detached
,并且这对于所有非导航属性都适用。
对于跟踪的实体,我可以直接更新 FK ID 属性,但如果它一开始是分离的,则必须通过导航属性进行更新。由于某种原因,这也会导致UPDATE
为每个相关实体运行一个语句,而不仅仅是我期望的多对多表。
跟踪实体:
// This will save to the DB
job.PrimaryAccountId = 123;
最初分离的实体:
// This will NOT save to the DB
job.PrimaryAccountId = 123;
// This will not save to the DB
job.PrimaryAccount.AccountId = 123;
在执行上述任一操作后更新并保存:
await _dataAccess.Update(job);
await _dataAccess.SaveChangesAsync();
此操作应被视为非法,因此如果该实例被跟踪,则在缓存实例中执行此操作将非常糟糕。
您的目标是将作业关联到不同的帐户,而不是更新现有帐户以更改其 ID。(如果是PK,那是不允许的)
处理独立的实体可能会变得混乱。处理分离的实体图(相关实体)肯定会变得更加混乱。
如果您已加载作业及其关联的主帐户,并在缓存中分离了这些引用,则重新附加这些引用将导致问题。例如,如果我执行以下操作:
...然后我缓存了它,并且一些代码更新了作业:
现在我们有一个问题。该作业有一个指向旧帐户的导航属性,但我们更改了作业的 FK。如果要更新分离的实体,则需要先删除所有导航属性引用,然后再调用
Update
:..从这里您可以致电:
但是,如果您需要/想要缓存副本中的关联帐户,则需要重新获取关联实体以更新该缓存作业条目。
最终,我不建议在外部缓存实体,而是按需加载实体并更新其跟踪的引用。缓存带来的问题比它看起来能解决的问题还要多。
Update()
自动将覆盖实体的所有UPDATE
值,而不仅仅是更改的值,并且即使实际上没有任何更改,也会执行语句。您还会使系统面临过时数据覆盖或更频繁的并发异常。引入缓存的理由几乎总是为了避免额外的数据库往返。这对于读取操作当然很有价值,但不应该成为更新操作的一个因素。获取单个实体,甚至它的相关数据都非常快,有助于检测和避免陈旧数据覆盖,并通过更改跟踪器提高更新效率,仅针对更改的值(如果确实有任何更改)生成 Update 语句。