2015-09-05 65 views
2

我寫一個簡單的事件策劃的Web應用程序(使用BreezeJS /實體框架) - 用戶創建一個比賽實體,並要求服務器產生一個或多個建議計劃(只有我一個這篇文章的目的) 。BreezeJS:爲什麼Before/AfterSaveEntitiesDelegate中的刪除操作不會傳播回客戶端?

當用戶點擊「生成計劃」時,比賽(包括生成計劃所需的大量細節)應提交給服務器,服務器應刪除任何現有計劃,生成一個新計劃,應該更新側面模型。

完美契合命名爲save,我想!

問題是最後一步:更新客戶端模型。服務器添加的計劃實體按預期在客戶端中顯示,但刪除被忽略。即客戶最終以新舊計劃結束!

這裏是我的名爲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);); 
    } 
} 

我試圖使用named-saving做他們不打算做的事情(即刪除和添加實體)嗎?

PS:我試着做一個明確的加法並保存使用readonlyContext和_contextProvider.Context,但真的沒有工作。

編輯:

如果我試圖從DB明確刪除舊的計劃像下面,什麼都不會發生:

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

我猜這是因爲_contextProvider.Context已經老計劃在緩存中,所以刪除它「背後」(即使用另一個上下文)並沒有什麼區別。

如果我然後嘗試使用_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),這是我直接在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 
    } 
] 

在此迴應,被刪除的實體永遠不會出現,所以客戶端可以理解它保留在模型中。

增加的計劃(Id 11)確實出現,並且集成在客戶端模型中。

但是:從sbelinis的回答來看,以Server added object showing as added in client after save changes,所添加的計劃看來可能是一個機緣巧合的事實:

在你的具體的例子,保存,因爲它發生在製作成新的實體與BeforeSaveEntity方法的實體有關,但不應該依賴它。

但sbelinis例如如何正確添加實體出現不完整的(例如,它指的是其他地方沒有使用的局部變量saveMapAdditions)

回答

0

OK,我想通了,如何解決這個!

我仍然無法將刪除反映回客戶端緩存中......但是如果我的服務器端代碼也從所有關係中刪除刪除的實體,則刪除將反射回來,並且實體將從客戶端模型。

更新的代碼(我已經添加了聲明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);); 
    } 
} 

當然,如果你搜索計劃實體客戶端本地緩存中,我懷疑被刪除的計劃仍然會出現,所以它不是完善。但它適用於我!

+0

我接受我自己的答案。我不確定這是否是一種糟糕的形式 - 填充自己的背部 - 但它確實描述了我的問題的解決方案... –

相關問題