3
votes

Given a fairly standard scenario in an application, of having a list of entities that can be added/edited/deleted etc. When I first load the page, I query the entites with breeze. All good. If I edit an entity, breeze sees this and the entity is saved AND updated in the cache, so when I return to the page with the list, the item shows any relevant changes. If I delete an entity, breeze will again save that change AND update it's cache so the entity no longer appears when I return to the list page and requery the data (locally from the cache I should point out).

However, if I add a new entity, it does not appear on the list page (assuming it satisfies the requirements of the query). I'm guessing that breeze is caching the results of a query specific to that query, rather than actually querying the cache (does that make sense)?

Assuming that is the case, is there a way of telling breeze to remove or invalidate cache items relating to a specific entity type, as opposed to clearing the cache completely? I can always avoid querying the cache and go directly to the server, but that seems a waste when I know breeze has the newly created entity in the cache, it just isn't showing it to me.

I use a single method for a lot of my queries, so it may just be the way I'm handling the local querying in that method, therefore I have included it below, in case that is the cause.

var defaultQuery = function (observable, resourceName, orderby, where, expand, forceRemote, localEntityName, localCountThreshold, page, count) {
            var query = EntityQuery.from(resourceName);
            if (orderby) {
                query = query.orderBy(orderby);

                if (page) {
                    query = query.skip(pageSize * (page()));
                    query = query.take(pageSize);
                    query = query.inlineCount();
                }
            }
            if (where)
                query = query.where(where);
            if (expand)
                query = query.expand(expand);

            if (!forceRemote) {
                if (localEntityName) {
                    query = query.toType(localEntityName);
                }
                var localResult = manager.executeQueryLocally(query);
                if (localCountThreshold) {
                    if (localResult.length > localCountThreshold) {
                        observable(localResult);
                        return Q.resolve();
                    }
                } else {
                    if (localResult.length > 0) {
                        observable(localResult);
                        return Q.resolve();
                    }
                }
            }

            return query.using(manager)
                .execute()
                .then(function (data) {
                    if (observable) {
                        observable(data.results);
                    }
                    if (count) {
                        count(data.inlineCount);
                    }
                    var logMsg = 'Retrieved ' + resourceName + ' from remote data source with order by {' + orderby + '}, where clause {' + where + '} and expand properties {' + expand + '}';
                    if (page)
                        logMsg += ' for page {' + page() + '} with total record count {' + count() + '}';
                    log(logMsg, data, true);
                })
                .fail(queryFailed);
        };

Usually in questions like this, I have just misunderstood some aspect of how breeze works, so if anyone can correct me, I'd be very appreciative.

Thanks!


Update

I have included the flow of actions step by step to show in more detail what I meant.

  1. Execute Query for all objects
  2. Query is executed locally first, returns nothing as no cache data exists.
  3. Query is then executed against the database - returns [A,B,C]
  4. Edit A - rename to AA - call saveChanges()
  5. Execute same query for all objects
  6. Query is executed locally first, returns [AA,B,C]
  7. Query skips executing against database as results have been found from cache.
  8. Delete B (setDeleted()) - call saveChanges()
  9. Execute same query for all objects
  10. Query is executed locally first, returns [AA,C]
  11. Query skips executing against database as results have been found from cache.
  12. Create new entity - set name to D - call saveChanges()
  13. Execute same query for all objects
  14. Query is executed locally first, returns [AA,C] (does not include new D object!)

The point I'm trying to discover is that local queries return changes saved for edits and deletes, but not for add operations. I could remove entities from the cache by using setDetached as Jay suggested, but I would need to do that for all entities of a specific type one-by-one. That could be a big process.


Update again

It appears the behaviour I saw was the result of some mistake by myself. Having double and triple checked everything as a result of Jay's assertion that the results should be there (see below), the 'added' objects are now appearing, but I honestly can't explain what I did to prevent them in the first place.

1

1 Answers

3
votes

Just to be clear, Breeze updates the cache when you edit an entity, it does NOT save that entity until you call EntityManager.saveChanges(). So until you call "saveChanges" the cache and your database will be in different states.

What you might be seeing is the result of the idea that when you requery an entity that has already been changed in the EntityManager, the action of merging the server side data with the client side cache is controlled by the EntityQuery.queryOptions.mergeStrategy. By default, an EntityQuery has a MergeStrategy of PreserveChanges which means that a server side result will NOT overwrite any "modified" records in the cache.

Per the later part of your post, you can remove any entity from the local cache simply by calling the entity's "entityAspect.setDetached" method.