BreezeJS:为什么在 Before/AfterSaveEntitiesDelegate 中进行的删除没有传播回客户端?



我正在编写一个简单的事件规划web应用程序(使用BreezeJS/实体框架)-用户创建一个锦标赛实体,并要求服务器生成一个或多个建议的计划(只是一个为这篇文章的目的)。

每当用户点击"生成计划"时,比赛(包括生成计划所需的大量细节)应提交给服务器,服务器应删除任何现有计划,生成新计划,并更新客户端模型。

非常适合名为save的,我想!

问题是最后一步:更新客户端模型。服务器添加的计划实体在客户机中按预期显示,但是删除被忽略。也就是说,客户端最终得到了新的和旧的计划!

这是我的命名保存:

[注意:这个问题的描述和代码省略了很多不相关的细节(比如20个属性和实体类型),以保持问题的大小]

[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 https://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););
        var addPlan = new Plan {TournamentId = tournament.Id, };
        arg[typeof(Plan)].Add(_contextProvider.CreateEntityInfo(addPlan, EntityState.Added););
    }
}

我试图使用命名保存的东西,他们不打算做(即删除和添加实体)?

PS:我尝试做一个显式的添加和保存使用readonlyContext和_contextProvider。上下文,但是真的不起作用。

编辑:

如果我尝试像下面这样显式地从DB中删除旧的计划,什么也不会发生:

        arg[typeof(Plan)].Add(_contextProvider.CreateEntityInfo(deletePlan, EntityState.Deleted););
        // Add this:
        context.PlanEntries.Remove(deletePlan);
        context.SaveChanges();

我猜是因为_contextProvider。上下文已经在缓存中有旧的计划,所以"在背后"删除它(即使用另一个上下文)不会产生影响。

如果我然后尝试删除它使用_contextProvider。上下文,我从框架得到一个奇怪的重复输入错误。

我已经无计可施了!

编辑2:

这是保存请求和响应中的数据,由ie开发人员工具记录。

请求:

{
    "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": { }
}

服务器然后删除现有的Plan条目(Id=10),并添加一个新的(Id=11),我直接在DB中使用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
    }
]

在此响应中,删除的实体从未出现,因此客户端可以理解地将其留在其模型中。

添加的Plan (Id 11) 不出现,并且集成在客户端模型中。

BUT:从shbelinis对Server added object的回答来看,在保存更改后客户端显示为已添加,添加的Plan出现的事实可能是一个幸运的巧合:

在您的特定示例中,新实体被保存,因为它恰好与beforeaveentity方法的实体相关,但您不应该依赖它。

但是,如何正确地添加实体的示例似乎不完整(例如,它引用了一个本地变量saveMapAdditions,而该变量在其他地方没有使用)

好了,我知道如何解决这个问题了!

我仍然不能得到删除反映回客户端缓存…但是,如果我的服务器端代码也从所有关系中删除了已删除的实体,则删除将被反射回来,并且实体将从客户端模型中消失。

更新后的代码(我添加了语句tournament.Plans.Remove(deletePlan)):

[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););
    }
}

当然,如果您在客户端本地缓存中搜索Plan实体,我怀疑删除的计划仍然会出现,因此它并不完美。但它对我有用!

最新更新