我在Angular2中使用BreezeJS,并注意到多次调用MetaData调用。
我试图通过在我的BreezeDataService的构造函数上调用fetchMetadata()来填充缓存,但是这没有区别(它添加了另一个元数据调用)。
this.entityManager.fetchMetadata().then(function () { console.log('entityManager.fetchMetadata finished'); });
我认为它是由主页加载时发出的5个数据请求引起的,每个请求都会在不等待现有元数据调用完成的情况下获取元数据。
您可以使用NetWorks工具在www.quemesa.com上看到问题:(前5个是PReflight CORS请求)
如何告诉代码等待任何现有元数据调用完成而不是再次获取它?
使用代码更新:
@Injectable()
export class DataBreezeService {
public isSaving: boolean = false;
public entityManager: EntityManager;
constructor(private spinnerService: SpinnerService, private loggerService: LoggerService) {
this.entityManager = new EntityManager(environment.webApiServiceUrl);
this.entityManager.metadataStore.namingConvention = NamingConvention.camelCase;
this.entityManager.fetchMetadata().then(() => this.loggerService.info('entityManager.fetchMetadata finished'));
}
public executeQueryArray(query: EntityQuery) {
return this.entityManager.executeQuery(query)
.then((queryResult: QueryResult) => this.successArrayDataLoad(queryResult))
.catch((error) => this.errorDataLoad(error))
}
然后我有不同的使用DataBreezeService的实体服务:
@Injectable()
export class BookingService {
constructor(private dataBreezeService: DataBreezeService, private loggerService: LoggerService) {
}
public getBookingsForUser(userId: number, forceServerCall: boolean = false) {
this.dataBreezeService.initialiseQuery('getBookingsForUser', [userId], forceServerCall);
let query = new EntityQuery()
.from("bookings")
.where("createdByUserId", "==", userId)
.where("visibilityId", "==", Status.Active) //booking is active
.toType('Booking')
.expand('createdByUser, restaurant, restaurant.suburb, restaurantScheduleDiscount, rating')
.orderBy("bookingDate Desc")
.inlineCount(); //return total
return this.dataBreezeService.executeQueryArray(query);
}
答案 0 :(得分:0)
我和我的团队想出了解决这个问题的方法。我会尽力解释我们是如何做到的。我们的更改涉及到breeze.debug.js的自定义。这个很重要!由于这涉及对Breeze.js的更改,如果您升级到新版本的Breeze.js,请准备好再次进行更改!
IndexedDB比使用localStorage更具挑战性,我们这样做是因为我们在网络工作者中运行Breeze - 并且Web工作者中没有本地存储。只有IndexedDB是。
1)我们在indexedDB数据库中检查proto.fetchMetadata中的元数据。如果未找到(或不支持indexedDB),则该方法将回退到默认行为。
2)如果支持IndexedDB,在proto.ajaxMetaData中的Ajax调用的成功承诺中,我们将元数据写入IndexedDB数据库。
请仔细考虑您希望在IndexedDB中保留元数据缓存多长时间。是每次会议吗?每个新构建(可能包含新元数据)?您可能希望创建一个定期删除元数据缓存的脚本。我们有代码返回网站DLL的DLL版本信息 - 我们将其与本地存储密钥进行比较,以确定我们是否有新版本。这是限制性最小的策略......只有在新的构建正在运行时才会清除缓存。
但是,您可能希望每次用户创建新会话时清除缓存。无论哪种方式,您为每个IndexedDB条目使用的密钥都应该是唯一的 - 包含路由,数据上下文(如果重置那么重要,还可以选择sessionid)。
您可以使用非常长的字符串作为键。我建议创建一个javascript对象,其中包含键的所有唯一部分(route,dllVersion,UserId),然后将对象转换为JSON字符串 - 并将该字符串用作IndexedDB键。
即使您没有应用元数据的缓存,您也应该在加载请求的元数据时至少广播一个事件,如下所示:
$rootScope.$broadcast('MetaDataLoaded' + serviceRoute, dataContext);
我们有一个包装类,它在元数据完全加载时广播此事件。如果您不使用包装器,您可能希望将广播放在proto.ajaxMetaData中,或者如果实现缓存,则在从IndexedDB缓存返回元数据之前将其广播。
在你的呼叫控制器中,使用它来监听该事件:
$scope.$on('MetaDataLoadedServiceRoute', function (event, args) {
$scope.setup();
});
这使您可以在控制器中发出第一个请求之前等待元数据。
祝你好运!答案 1 :(得分:0)
您是否真的说同一个EntityManager
实例会发出多个元数据请求?我不记得是这样的。
如果确实如此,(a)我们应该修复 - 提出问题 - 以及(b)您可以在数据服务中解决它。
你有数据服务,对吗?您的组件永远不应该直接与EM通信,而是通过中间服务来隔离组件与管理器的直接联系,并将交互抽象为语义。无论是否使用Breeze,您都会在Angular应用程序中看到无处不在的建议。
假设您正在遵循该建议,您可以在初始化步骤中获取元数据,保留承诺,并通过已解决的承诺链接所有后续调用。
在您的应用中进行初始化步骤可能更简单,该步骤利用了元数据承诺和任何其他预加载缓存的启动活动。
您还可以在服务器上预先缓存元数据,并通过JavaScript标记将其加载为JSON-ish。这方面的例子在Breeze docs中。
为您提供了很多选择。
最后的想法。您创建了多少EntityManager
个?默认情况下,每个都将获取元数据。大多数人只需要一个,但有理由想要更多。如果您需要更多,请确保将其指定为" master"并使用复制构造函数创建其他构建器。