关于c#:Entity Framework Lookup表update / create

Entity Framework Lookup table update / create

本问题已经有最佳答案,请猛点这里访问。

我有这个创建方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
[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);
}

如您所见,创建团队时,我需要将颜色添加到查找表中。为此,我从数据库中获取颜色,然后根据作为模型一部分传递的颜色对它们进行过滤。

这告诉实体框架,这些颜色不是新的实体,因此它只是在查阅表格中创建一个引用,而不是创建新的颜色。

现在我想对更新方法做同样的事情。

我试过这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
[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);
}

但它不起作用。我有一个错误说明:

Collection was modified; enumeration operation may not execute.

< /块引用>

我知道这是在谈论颜色,但我不知道如何绕过它。

也许有人也遇到过类似的问题并设法解决了?


不能同时迭代集合并更改它。如果你真的想这样做,你必须把所有的值存储到一个不会被修改的地方。最简单的方法是在迭代通过之前对集合使用ToArray()ToList()

1
2
3
4
5
6
7
8
9
10
11
12
...
// 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());
...

这里的问题是,您正在更改要迭代的集合。

如果要从集合中删除(或添加)项,必须分两步执行:

  • 选择要删除的对象
  • 移除对象
  • 如果您的集合是列表,则可以使用List.RemoveAll方法


    好吧,在这里的2条评论和搜索之后,我想到了这个:

    1
    2
    3
    4
    // 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);

    很好用。