2015-04-21 40 views
1

我有這個創建方法:實體框架查找表更新/創建

[HttpPost] 
[Route("")] 
/// <summary> 
/// Create a team 
/// </summary> 
/// <param name="model">The team model</param> 
/// <returns>The modified team model</returns> 
public async Task<IHttpActionResult> Create(TeamBindingViewModel model) 
{ 

    // If our model is invalid, return the errors 
    if (!ModelState.IsValid) 
     return BadRequest(ModelState); 

    // Get all our colours 
    var colours = await this.colourService.GetAllAsync(); 

    // Create our new model 
    var team = new Team() 
    { 
     Name = model.Name, 
     Sport = model.Sport 
    }; 

    // For each colour, Add to our team 
    team.Colours = colours.Where(m => model.Colours.Any(c => c.Id == m.Id)).ToList(); 

    // Create our team 
    this.service.Create(team); 

    // Save our changes 
    await this.unitOfWork.SaveChangesAsync(); 

    // Assign our Id to our model 
    model.Id = team.Id; 

    // Return Ok 
    return Ok(model); 
} 

正如你所看到的,創建一個的時候,我需要添加顏色查找表。爲此,我從數據庫中獲取顏色,然後使用作爲模型一部分傳遞的顏色對它們進行過濾。

這告訴實體框架,這些顏色沒有新的實體,所以它只是創造,而不是創造新的顏色在查找表中的參考。

現在我想爲update方法做同樣的事情。

我嘗試這樣做:

[HttpPut] 
[Route("")] 
/// <summary> 
/// Update a team 
/// </summary> 
/// <param name="model">The team model</param> 
/// <returns>The modified team model</returns> 
public async Task<IHttpActionResult> Update(TeamBindingViewModel model) 
{ 

    // If our model is invalid, return the errors 
    if (!ModelState.IsValid) 
     return BadRequest(ModelState); 

    // Get our current team 
    var team = await this.service.GetAsync(model.Id, "Colours"); 

    // Get all our colours 
    var colours = await this.colourService.GetAllAsync(); 

    // Make changes to our team 
    team.Name = model.Name; 
    team.Sport = model.Sport; 

    // For each colour in our team colours but not in our model colours, remove 
    foreach (var colour in team.Colours) 
     if (!model.Colours.Any(c => c.Id == colour.Id)) 
      team.Colours.Remove(colour); 

    // For each colour that has to be added, add to our team colours 
    if (model.Colours != null) 
     foreach (var colour in model.Colours) 
      if (!team.Colours.Any(c => c.Id == colour.Id)) 
       team.Colours.Add(colours.Where(m => m.Id == colour.Id).SingleOrDefault()); 

    // Update the team 
    this.service.Update(team); 

    // Save our changes 
    await this.unitOfWork.SaveChangesAsync(); 

    // Return Ok 
    return Ok(model); 
} 

但沒有奏效。我得到一個錯誤,說明:

收集被修改;枚舉操作可能不會執行。

我知道它在談論顏色,但我不知道如何解決它。

也許有人有類似的問題,並設法解決它?

回答

1

您不能迭代收集並同時更改它。如果你真的想這樣做,你必須將所有的值存儲到一些沒有被修改的地方。最簡單的方法是在迭代之前在集合上使用ToArray()ToList()

... 
// For each colour in our team colours but not in our model colours, remove 
foreach (var colour in team.Colours.ToList()) // <<== note change here 
    if (!model.Colours.Any(c => c.Id == colour.Id)) 
     team.Colours.Remove(colour); 

// For each colour that has to be added, add to our team colours 
if (model.Colours != null) 
    foreach (var colour in model.Colours.ToList()) // <<== note change here 
     if (!team.Colours.Any(c => c.Id == colour.Id)) 
      team.Colours.Add(colours.Where(m => m.Id == colour.Id).SingleOrDefault()); 
... 
1

這裏的問題是你正在改變你正在迭代的集合。

如果你想從一個集合中刪除(或增加)的項目,你必須這樣做,在2個步驟:

  1. 選擇要刪除
  2. 刪除對象的對象

如果您的收藏是一個列表,您可以使用List.RemoveAll方法

+0

你能舉個例子,我不能讓這個去工作 – r3plica

+1

想通了:) – r3plica

-1

好了,在這裏做了一些搜索的2條評論後,我想出了這一點:

// Loop through our colours and remove the ones that are not in our new colour list 
for (var i = 0; i < team.Colours.Count; i++) 
    if (!model.Colours.Any(c => c.Id == team.Colours[i].Id)) 
     team.Colours.RemoveAt(i); 

它完美的作品。

+0

這段代碼是錯誤的,如果任何元素將被刪除,將跳過集合中的一些項目。例如:你有'var arr = [「a」,「b」,「c」]'並且在第一次迭代中('i = 0'),你移除位置0處的元素(元素''a「')。在此之後,所有的數組元素將向上移動一個位置,數組將爲'[「b」,「c」]'。因此,在下一次迭代('i = 1')中,您將檢查位置1處的元素,它將是''c「'而不是''b」'。這是錯誤的。要解決這個問題,你必須從底部移到頂部。 –

+0

我可以看到你在說什麼,但我已經測試過了。我選擇了前三項,然後將其保存到數據庫中。然後我編輯了記錄並取消選擇了第一個項目並選擇了另一個項目,它工作正常。於是我再次編輯並取消選擇所有內容,並選擇了一套新的顏色,它仍然有效。 – r3plica

+0

嘗試在同一時間移除兩個數組中相鄰的另一個顏色(讓我們先說和第二個),你會明白我的意思。第二種顏色將被跳過,不會被刪除。或者 - 嘗試以下方法1)添加所有顏色並更新; 2)刪除所有顏色並更新;你會看到每一個第二種顏色都不會被移除 –