BreezeJS:为什么在Before/AfterSaveEntitysDelegate中进行的删除没有传播回客户端?
我正在使用BreezeJS/Entity框架编写一个简单的活动规划web应用程序-用户创建一个锦标赛实体,并要求服务器生成一个或多个建议计划,其中一个用于本文目的 每当用户单击generate plan时,应将包含生成计划所需的大量详细信息的比赛提交给服务器,服务器应删除任何现有计划,生成新计划,并更新客户端模型 我想,这是一次名副其实的扑救 问题是最后一步:更新客户端模型。服务器添加的计划实体在客户端中按预期显示,但忽略删除。也就是说,客户最终会得到新的和旧的计划 这是我的名字save: [注:本问题中的描述和代码省略了许多不相关的细节,如20个属性和实体类型,以保持问题的规模] 我猜这是因为_contextProvider.Context已经在缓存中有了旧的计划,所以在它背后删除它(即使用另一个上下文)并没有什么区别 如果然后尝试使用_contextProvider.Context删除它,我会从框架中得到一个奇怪的重复条目错误 我束手无策 编辑2: 以下是IEs开发人员工具记录的保存请求和响应中的数据 首先请求:BreezeJS:为什么在Before/AfterSaveEntitysDelegate中进行的删除没有传播回客户端?,breeze,Breeze,我正在使用BreezeJS/Entity框架编写一个简单的活动规划web应用程序-用户创建一个锦标赛实体,并要求服务器生成一个或多个建议计划,其中一个用于本文目的 每当用户单击generate plan时,应将包含生成计划所需的大量详细信息的比赛提交给服务器,服务器应删除任何现有计划,生成新计划,并更新客户端模型 我想,这是一次名副其实的扑救 问题是最后一步:更新客户端模型。服务器添加的计划实体在客户端中按预期显示,但忽略删除。也就是说,客户最终会得到新的和旧的计划 这是我的名字save: [注
{
"entities": [
{
"Id": 1,
"EventName": "Test Tournament",
"EventTime": "2015-03-21T20:00:00.000Z",
"entityAspect": {
"entityTypeName": "Tournament:#Pontifex.Model",
"defaultResourceName": "Tournaments",
"entityState": "Unchanged",
"originalValuesMap": { },
"autoGeneratedKey": {
"propertyName": "Id",
"autoGeneratedKeyType": "Identity"
}
}
}
],
"saveOptions": { }
}
然后,服务器删除现有的计划条目Id=10,并添加一个新的Id=11,我直接在数据库中使用SELECT进行了验证。那很好
但答案是:
[
{
"$id": "1",
"$type": "Pontifex.Model.Tournament, Pontifex.Server",
"Id": 1,
"EventName": "Test Tournament",
"EventTime": "2015-03-21T20:00:00.000",
"Plans": [
{
"$id": "17",
"$type": "Pontifex.Model.Plan, Pontifex.Server",
"Id": 11,
"TournamentId": 1,
"Tournament": { "$ref": "1" }
}
],
"BoardPlan": null
}
]
在这个响应中,删除的实体从未出现,因此客户机将其留在其模型中是可以理解的
添加的计划Id 11将显示,并集成到客户机模型中
但是:从斯贝利斯的回答来看,增加的计划似乎是一个幸运的巧合:
在您的特定示例中,新实体被添加到save中,因为它碰巧与BeforeSaveEntity方法的实体相关,但您不应该依赖它
但是sbelin是一个如何正确添加实体的示例,它似乎不完整,例如,它引用了一个局部变量saveMapAdditions,而该变量在其他地方不使用 我仍然无法将删除操作返回到客户端缓存中……但是如果我的服务器端代码也从所有关系中删除了删除的实体,则删除操作将返回,并且该实体将从客户端模型中消失 更新后的代码我添加了语句Tornament.Plans.RemovedeletePlan:
当然,如果在客户端本地缓存中搜索计划实体,我怀疑删除的计划仍然会出现,因此它不是完美的。但它对我有用 我接受我自己的答案。我不确定这是否是一个糟糕的形式-在背后填充你自己-但它确实描述了我问题的解决方案。。。
{
"entities": [
{
"Id": 1,
"EventName": "Test Tournament",
"EventTime": "2015-03-21T20:00:00.000Z",
"entityAspect": {
"entityTypeName": "Tournament:#Pontifex.Model",
"defaultResourceName": "Tournaments",
"entityState": "Unchanged",
"originalValuesMap": { },
"autoGeneratedKey": {
"propertyName": "Id",
"autoGeneratedKeyType": "Identity"
}
}
}
],
"saveOptions": { }
}
[
{
"$id": "1",
"$type": "Pontifex.Model.Tournament, Pontifex.Server",
"Id": 1,
"EventName": "Test Tournament",
"EventTime": "2015-03-21T20:00:00.000",
"Plans": [
{
"$id": "17",
"$type": "Pontifex.Model.Plan, Pontifex.Server",
"Id": 11,
"TournamentId": 1,
"Tournament": { "$ref": "1" }
}
],
"BoardPlan": null
}
]
[HttpPost]
public SaveResult MyNamedSave(JObject saveBundle)
{
_contextProvider.BeforeSaveEntitiesDelegate = RecalculatePlan;
return _contextProvider.SaveChanges(saveBundle);
}
private Dictionary<Type, List<EntityInfo>> RecalculatePlan(Dictionary<Type, List<EntityInfo>> arg)
{
// See http://stackoverflow.com/questions/14517945/using-this-context-inside-beforesaveentity:
var readonlyContext = new PontifexContext();
foreach (var eventInfo in arg[typeof(Tournament)])
{
var tournament = (Tournament)eventInfo.Entity;
var deletePlan = readonlyContext.Plans.First(p => p.TournamentId == tournament.Id);
arg[typeof(Plan)].Add(_contextProvider.CreateEntityInfo(deletePlan, EntityState.Deleted););
// Workaround: Remove the deleted plan from all relations:
tournament.Plans.Remove(deletePlan);
var addPlan = new Plan {TournamentId = tournament.Id, };
arg[typeof(Plan)].Add(_contextProvider.CreateEntityInfo(addPlan, EntityState.Added););
}
}