我们正在调查使用Breeze进行某些工具的现场部署。情况是这样的 - 审计员将访问现场的网站,在那里大多数时间将没有 - 或非常退化 - 互联网访问。我们希望使用Breeze来缓存数据,然后将其存储在本地,以便在没有可用连接时可以访问,而不是在所有笔记本电脑和平板电脑上复制我们的SQL数据库(如果可能的话):
不幸的是,在缓存任何大量数据时,Breeze似乎都在窒息。通常在Chrome上,它的实体价值介于8到13MB之间(通过HTTPResponse标头衡量)。这可能会有所改变,具体取决于我打开了多少个标签等,但我无法将其移动超过10%。我得到的错误是Chrome标签崩溃并告诉我重新加载。该错误是可复制的(我以100K块的形式下载数据并且每次都在相同的读取时失败并且如果我在上一次读取后停止它则工作正常)当我改变页面大小时,它总是在相同的范围内失败。
这是Breeze或Chrome的限制吗?还是窗户?我在Firefox上试过它,它在整个浏览器崩溃之前处理更少的数据。 IE的价格好一点,但没有一个能做得很好。
查看任务管理器中的性能,我得到以下结果:
我可以用任何选择标准计算下载多少,但我找不到计算任何特定浏览器实例可以处理多少数据的方法。这使得使用Breeze进行离线审计几乎无用。
还有其他人解决了这个问题吗?处理这类事情的最佳方法是什么?我想过几件事,但没有一件是理想的。任何想法都将不胜感激。
史蒂夫施密特的要求:
以下是一些有用的链接:
第一个查询,只是为了填充页面上的标签,可以快速运行并下载最少的数据:
var query = breeze.EntityQuery
.from("Countries")
.orderBy("Name")
.expand("Regions.Districts.Seasons, Regions.Districts.Sites");
一旦用户选择了他/她希望缓存的网站,就会启动以下两个查询(以前是一个查询,但我把它分成两个,希望它对资源的负担更小 - 它没有帮助)。第一个查询(通常是2-3K实体和大约2MB)按预期运行。列出的谓词的某些组合用于过滤数据。
var qry = breeze.EntityQuery
.from("SeasonClients")
.expand("Client,Group.Site,Season,VSeasonClientCredit")
.orderBy("DistrictId,SeasonId,GroupId,ClientId")
var p = breeze.Predicate("District.Region.CountryId", "==", CountryId);
var p1 = breeze.Predicate("SeasonId", "==", SeasonId);
var p2 = breeze.Predicate("DistrictId", "==", DistrictId);
var p3 = breeze.Predicate("Group.Site.SiteId", "in", SiteIds);
第一个查询运行后,第二个查询(下面)运行(也使用列出的谓词的某些组合来过滤数据。大约9MB,它将有大约50K行下载)。当两个查询之间的总下载负担介于10MB和13MB之间时,浏览器将崩溃。
var qry = breeze.EntityQuery
.from("Repayments")
.orderBy('SeasonId,ClientId,RepaymentDate');
var p1 = breeze.Predicate("District.Region.CountryId", "==", CountryId);
var p2 = breeze.Predicate("SeasonId", "==", SeasonId);
var p3 = breeze.Predicate("DistrictId", "==", DistrictId);
var p4 = breeze.Predicate("SiteId", "in", SiteIds);
谢谢你的兴趣,史蒂夫。您应该知道实体关系是继承的,并且当前正在生产中,支持组织的大部分操作,因此尽可能少的更改是最好的。此外,希望将这一点从报告应用程序扩展到可以在现场完成数据输入的应用程序(因此,据我所知,使用预测来限制数据不起作用)。
感谢您的关注,如果您还有其他需要,请告诉我。
答案 0 :(得分:3)
根据我使用breeze在具有脱机功能的Web应用程序上构建的经验,以下是一些建议。部分或全部这些可能对您的用例没有意义......
确定需要编辑的实体类型与用于填充下拉列表的实体类型等。使用noTracking查询选项加载不可编辑的数据,并使用JSON.stringify将它们缓存在localStorage中。这避免了将数据强制转换为实体,更改跟踪等的开销。模型中此方法的良好候选者可能是实体类型,如国家,地区,区域,站点等。
如果可能,请在您的应用程序中提供一个工具,以便用户识别他们想要哪些记录以及#34;离线"。这样您就不需要加载和缓存所有内容,这可能会因为关系,实体,属性等的数量而变得非常昂贵。
结合建议#2,避免一次加载所有可编辑数据,并避免使用相同的EntityManager实例加载每组数据。例如,如果客户端实体需要在没有连接的字段中进行编辑,则创建新的EntityManager,加载单个客户端(扩展任何也需要编辑的子级)并将这些数据与其他客户端分开缓存
缓存breeze元数据一次。调用exportEntities时,includeMetadata参数应为false。有关此here的更多信息。
要创建新的EntityManager实例,请使用createEmptyCopy方法。
修改强>
我想回复此评论:
假设我有一个有账单和付款的客户。那个客户在 集团,在一个地点,在一个地区,在一个国家。你是说那个 客户,付款和账单信息可能都有自己的EM, 虽然位置层次结构可能位于没有跟踪的第4个EM中? 然后,当我提到它们时,我会根据需要使用连接关系 关于不同EM的LINQ(给我客户A的所有账单,给 我为客户支付的所有款项A)?
在决定如何分离事物方面,这是一个判断。我建议的一些内容可能有点过分,这实际上取决于数据量和应用程序的使用方式。
假设您不需要在离线时编辑群组,网站,区域和国家/地区,我首先要做的是使用noTracking选项加载群组列表并将其缓存在localStorage中离线使用。然后对网站,地区和国家/地区执行相同操作。请记住,加载了noTracking选项的实体未在实体管理器中缓存,因此您需要获取查询结果,JSON.stringify它然后调用localStorage.setItem。这里的目的是确保您的应用程序始终可以访问组,站点,区域等列表,以便在显示表单以编辑客户端实体时,您将拥有填充组所需的数据,网站,地区和国家选择/组合框/下拉列表。
假设用户已经确定了他们想要在离线时使用的客户端子集,我会一次一个地加载这些客户端(包括他们的付款和账单信息但不扩展他们的组,网站,区域,国家/地区)并使用entityManager.exportEntities缓存每个客户+付款+帐单。这里的推理是,每次要编辑特定客户端时,将多个客户端及其付款和账单加载到同一个EntityManager中是没有意义的。这可能是很多不必要的开销,但同样,这是一个判断调用。
答案 1 :(得分:1)
@ Jeremy的答案非常好,非常有帮助,但实际上并没有回答我开始认为无法回答的问题,或者至少是错误的问题。但是@Steve在评论中给了我最适合这个问题的信息。
既不是Breeze也不是浏览器,而是Knockout。显然,围绕微风实体的淘汰包装使用所有内存(至少在加载实体和我的环境时)。如上所述,Knockout / Breeze在阅读了大约5MB的数据后会瘫痪,导致Chrome崩溃,内存使用量超过1.7GB(预备下载内存使用量约为300MB)。在ANgularJS中重写应用程序消除了这个问题。到目前为止,我已经能够从完全相同的EF6型号下载50MB以上的Breeze / Angular,总的Chrome内存使用量从未超过625MB。
我将测试更大的有效载荷,但是满足我当前需求的50 MB以上。谢谢大家的帮助。