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

BreezeJS: Why aren't deletions made in Before/AfterSaveEntitiesDelegate propagated back to the client?

我正在编写一个简单的活动策划网络应用程序(使用 BreezeJS/Entity 框架)- 用户创建一个 tournament 实体,并要求服务器生成一个或多个建议计划(仅针对此 post 的目的)。

每当用户点击 "generate plan" 时,锦标赛(包括生成计划所需的大量详细信息)应提交给服务器,服务器应删除任何现有计划,生成新计划,然后应更新客户端模型。

非常适合命名保存,我想!

问题出在最后一步:更新客户端模型。服务端添加的计划实体如期出现在客户端,但删除被忽略。 IE。客户最终得到了新旧计划!

这是我命名的存档:

[注意:这个问题的描述和代码省略了很多不相关的细节(比如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 
    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.Context 进行显式添加和保存,但是 really 不起作用。

编辑:

如果我尝试从数据库中明确删除旧计划,如下所示,没有任何反应:

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

我猜这是因为 _contextProvider.Context 缓存中已经有旧计划,所以删除它 "behind its back"(即使用另一个上下文)没有什么不同。

如果我随后尝试使用 _contextProvider.Context 删除它,我会从框架中收到一个奇怪的重复输入错误。

我已经无计可施了!

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

服务器然后删除现有的计划条目 (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) 出现,并集成在客户端模型中。

BUT:从sbelinis对Server added object showing as added in client after save changes的回答来看,添加的Plan出现可能是巧合:

In your particular example, the new entity made into the save because it happened to be related to the entity of the BeforeSaveEntity method, but you should not rely on it.

但是关于如何正确添加实体的 sbelinis 示例似乎不完整(例如,它引用了一个局部变量 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 
    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););
    }
}

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