Обновление/создание таблицы поиска Entity Framework

58
5

У меня был этот метод создания:

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

Как вы можете видеть, когда создается Команда, мне нужно добавить Цвета в таблицу поиска. Для этого я получаю Цвета из базы данных, а затем фильтрую их по цветам, которые были переданы как часть модели.

Это сообщает Entity Framework, что эти цвета не являются новыми объектами, поэтому он просто создает ссылку в таблице поиска, а не создает новые цвета.

Теперь я хочу сделать то же самое для метода обновления.

Я попробовал это:

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

Но это не сработало. У меня возникла ошибка:

Коллекция была изменена; операция перечисления может не выполняться.

Я знаю, что речь идет о цветах, но я понятия не имею, как обойти это.

Возможно, у кого-то была аналогичная проблема и удалось ее исправить?

спросил(а) 2015-04-21T17:30:00+03:00 5 лет, 7 месяцев назад
1
Решение
61

Вы не можете выполнять итерацию по коллекции и изменять ее одновременно. Если вы действительно хотите это сделать, вы должны сохранить все значения в каком-то месте, которое не будет изменено. Самый простой способ - использовать 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());
...

ответил(а) 2015-04-21T17:37:00+03:00 5 лет, 7 месяцев назад
58

Проблема здесь в том, что вы меняете коллекцию, которую вы выполняете.

Если вы хотите удалить (или добавить) предметы из коллекции, вам нужно сделать это за 2 шага:


Выберите объекты, которые хотите удалить. Удалить объект

В случае, если ваша коллекция является списком, вы можете использовать метод List.RemoveAll

ответил(а) 2015-04-21T17:36:00+03:00 5 лет, 7 месяцев назад
-4

Хорошо, поэтому после 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);

который отлично работает.

ответил(а) 2015-04-21T18:06:00+03:00 5 лет, 7 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема