Breeze:当其他人删除子实体时,它们在重新加载父实体后仍会出现

Breeze:当其他人删除子实体时,它们在重新加载父实体后仍会出现,breeze,Breeze,我们有一个breeze客户机解决方案,其中显示了父实体及其子实体的列表。我们对一些子实体进行硬删除。现在,当用户执行删除操作时,没有问题,但是当其他人执行删除操作时,似乎无法使已加载到缓存中的子项无效。我们对父对象执行一个新的查询并扩展到子对象,但是breeze附加了它已经听说过的所有其他子对象,即使数据库没有返回它们 我的问题:breeze难道不应该意识到我们正在通过expand加载,从而在从db加载结果之前从缓存中完全删除所有子项吗?如果不是这样的话,我们还能如何做到这一点 谢谢这是一个有效

我们有一个breeze客户机解决方案,其中显示了父实体及其子实体的列表。我们对一些子实体进行硬删除。现在,当用户执行删除操作时,没有问题,但是当其他人执行删除操作时,似乎无法使已加载到缓存中的子项无效。我们对父对象执行一个新的查询并扩展到子对象,但是breeze附加了它已经听说过的所有其他子对象,即使数据库没有返回它们

我的问题:breeze难道不应该意识到我们正在通过expand加载,从而在从db加载结果之前从缓存中完全删除所有子项吗?如果不是这样的话,我们还能如何做到这一点


谢谢

这是一个有效的观点,但目前我们不会因为查询而从本地缓存中删除实体。但是这是一个合理的请求,因此请将其添加到breeze用户语音中


同时,您始终可以创建一个方法,在执行查询之前从缓存中删除相关实体,并让查询(使用expand)将它们添加回缓存

是的,这是一个非常好的观点

删除对于每个数据管理工作来说都是一个可怕的复杂问题。这是真的,无论你是否使用微风。这只会让人心痛不已。这就是为什么我推荐软删除而不是硬删除

但你不在乎我怎么想。。。所以我会继续

让我直说吧要正确实施缓存清理方案,没有简单的方法。我将描述我们可能如何做到这一点(我肯定忽略了一些细节),您将看到为什么这很困难,并且在反常的情况下,没有结果

当然,最有效的暴力方法是在查询之前将缓存吹走。如果你这样做的话,你最好不要缓存,但我想我应该提一下

“分离”实体问题 在我继续之前,请记住我刚才提到的技术,如果您的UI(或其他任何东西)包含对要删除的实体的引用,那么所有可能的解决方案都是无用的

哦,你会从缓存中删除它们的。但是现在保存对它们的引用的任何东西都将继续引用处于“分离”状态的实体对象—幽灵。确保这不会发生是你的责任;微风不知道,如果它知道的话,它也无能为力

第二次尝试 第二个不那么直率的方法(Jay建议)是

  • 首先将查询应用于缓存
  • 对结果进行迭代,并针对每个结果进行迭代
    • 沿“展开”路径拆离每个子实体
    • 拆离顶层实体
现在,当查询成功时,您就有了一条清晰的道路让它填充缓存

下面是一个简单的代码示例,它与ToDoList及其TodoItems的查询相关:

var query = breeze.EntityQuery.from('TodoLists').expand('TodoItems');

var inCache = manager.executeQueryLocally(query);
inCache.slice().forEach(function(e) {
    inCache = inCache.concat(e.TodoItems);
});

inCache.slice().forEach(function(e) {
    manager.detachEntity(e);
});
这种方法至少有四个问题:

  • 每个被查询的实体都是一个幽灵。如果您的UI显示任何查询的实体,它将显示重影。即使在服务器上根本没有触及该实体(99%的情况下),情况也是如此。太糟糕了。你必须重新粉刷整个页面

    你也许能做到。但在许多方面,这种技术几乎和第一种技术一样不切实际。这意味着在任何地方发生任何查询后,EverView都处于潜在的无效状态

  • 分离实体会产生副作用。依赖于您分离的实体的所有其他实体将立即(a)更改和(b)孤立。正如下文“孤儿”一节所解释的那样,要从中恢复并不容易

  • 此技术将清除您正在查询的实体中所有挂起的更改。我们将很快看到如何处理这个问题

  • 如果查询因某种原因失败(连接丢失?),那么您将无法显示任何内容。除非你记得你删除了什么。。。在这种情况下,如果查询失败,您可以将这些实体放回缓存中

  • 为什么要提到一种实用价值有限的技术?因为这是迈向第三阶段的一个步骤

    尝试#3-这实际上可能有效 我将要描述的方法通常被称为“标记和扫描”

  • 在本地运行查询并计算刚才描述的
    inCache
    实体列表。这一次,不要从缓存中删除这些实体。查询成功后,我们将删除保留在此列表中的实体。。。但不是现在

  • 如果查询的
    MergeOption
    为“PreserveChanges”(默认情况下为“PreserveChanges”),请从
    inCache
    列表(而不是从管理器的缓存!)中删除所有具有挂起更改的实体。我们这样做是因为无论服务器上实体的状态如何,这些实体都必须留在缓存中。这就是“保持变化”的含义

    我们本可以在第二种方法中这样做,以避免删除带有未保存更改的实体

  • 订阅
    EntityManager.entityChanged
    事件。在处理程序中,从
    inCache
    列表中删除“已更改的实体”,因为该实体由查询返回并合并到缓存中这一事实告诉您它仍然存在于服务器上。下面是一些代码:

    var handlerId = manager.entityChanged.subscribe(trackQueryResults);
    
    function trackQueryResults(changeArgs) {
        var action = changeArgs.entityAction;
        if (action === breeze.EntityAction.AttachOnQuery ||
            action === breeze.EntityAction.MergeOnQuery) {
            var ix = inCache.indexOf(changeArgs.entity);
            if (ix > -1) {
                inCache.splice(ix, 1);
            }
        }
    }
    
  • 如果查询失败,请忘记所有这些

  • 如果查询成功

  • 取消订阅:
    manager.entityChanged.unsubscribe(handlerId)

  • 使用孤立检测处理程序订阅

    var handlerId = manager.entityChanged.subscribe(orphanDetector);
    
    function orphanDetector(changeArgs) {
        var action = changeArgs.entityAction;
        if (action === breeze.EntityAction.PropertyChange) {
           var orphan = changeArgs.entity;
           // do something about this orphan
        }
     }
    
  • 分离保留在
    inCache
    列表中的每个实体

    inCache.slice().forEach(function(e) {
        manager.detachEntity(e);
    });
    
  • 取消订阅孤立检测处理程序

  • var handlerId = manager.entityChanged.subscribe(orphanDetector);
    
    function orphanDetector(changeArgs) {
        var action = changeArgs.entityAction;
        if (action === breeze.EntityAction.PropertyChange) {
           var orphan = changeArgs.entity;
           // do something about this orphan
        }
     }
    
    孤立探测器? 拆离实体可能会产生副作用。假设我们有
    产品