在 Entity Framework 中编辑多对多。可以添加但不能删除
Editing Many to Many in Entity Framework. Can add but not remove
在我的 POST 编辑功能中,我的视图模型包含我要更新的游戏和我要添加到游戏中的平台 ID 列表。
使用此代码,我能够将平台添加到我的游戏中,但无法删除它们。我在末尾放置了一个断点,肯定会看到 viewModel.Game.Platforms 只有我选择的内容,但它没有在我的游戏列表中更新。
如果我添加几个平台并同时删除一些。添加了新平台,但删除了 none。
public ActionResult Edit(GameViewModel viewModel)
{
if (ModelState.IsValid)
{
List<Platform> platforms = new List<Platform>();
foreach (var id in viewModel.PostedPlatforms.PlatformIds)
{
platforms.Add(db.Platforms.Find(Int32.Parse(id)));
}
db.Games.Attach(viewModel.Game);
viewModel.Game.Platforms = platforms;
db.Entry(viewModel.Game).State = EntityState.Modified;
UpdateModel(viewModel.Game);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel.Game);
}
型号class是
public class Game
{
public int GameId { get; set; }
public string Title { get; set; }
public List<Platform> Platforms { get; set; }
}
public class Platform
{
public int PlatformId { get; set; }
public string Name { get; set; }
public List<Game> Games { get; set; }
}
根据 ourmandave 的建议,我得到了这段代码,虽然它确实改变了平台选择,但它每次都会创建一个新的游戏入口,这很低效,而且还会增加内容的 id,这会弄乱书签。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(GameViewModel viewModel)
{
if (ModelState.IsValid)
{
List<Platform> platforms = new List<Platform>();
if(viewModel.PostedPlatforms != null)
{
foreach (var id in viewModel.PostedPlatforms.PlatformIds)
{
platforms.Add(db.Platforms.Find(Int32.Parse(id)));
}
}
db.Games.Remove(db.Games.Find(viewModel.Game.PostId));
db.SaveChanges();
viewModel.Game.Platforms = platforms;
db.Games.Add(viewModel.Game);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel.Game);
}
你可以试试这个...
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(GameViewModel viewModel)
{
if (ModelState.IsValid)
{
List<Platform> selectedPlatforms = viewModel.Select(pl => GetPlatformById(pl.Id)).ToList();
var game = GetGameById(viewModel.Id);
UpdateGamePlatforms(game, selectedPlatforms);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel.Game);
}
private Platform GetPlatformById(int platformId)
{
return db.Platforms.First(pl => pl.Id == platformId);
}
private Game GetGameById(int gameId)
{
return db.Games.First(g => g.Id == gameId);
}
private void UpdateGamePlatforms(Game game, IList<Platform> selectedPlatforms)
{
var gamePlatforms = game.Platforms.ToList();
foreach (var gamePlatform in gamePlatforms)
{
if (selectedPlatforms.Contains(gamePlatform) == false)
{
game.Platforms.Remove(gamePlatform);
}
else
{
selectedPlatforms.Remove(gamePlatform);
}
}
game.Platforms.AddRange(selectedPlatforms);
}
UpdateGamePlatforms
将从游戏中删除不再选择的平台。它将保留仍处于选中状态的平台,并且还会向已选中的游戏添加新平台。
解决方案:使用 TomJerrum 的解决方案,我现在可以正确编辑平台列表。要更新其余属性,我必须映射我尝试编辑的游戏对象的所有 属性 以匹配我的 viewModel 的 属性。值得庆幸的是,已经有一个功能,所以我只需要添加 db.Entry(game).CurrentValues.SetValues(viewModel.game);.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(GameViewModel viewModel)
{
if (ModelState.IsValid)
{
List<Platform> selectedPlatforms = new List<Platform>();
if (viewModel.PostedPlatforms != null)
{
int[] platformIds = Array.ConvertAll(viewModel.PostedPlatforms.PlatformIds, p => Convert.ToInt32(p));
selectedPlatforms.AddRange(db.Platforms.Where(item => platformIds.Contains(item.PlatformId)).ToList());
}
var game = GetGameById(viewModel.Id);
UpdateGamePlatforms(game, selectedPlatforms);
db.Entry(game).CurrentValues.SetValues(viewModel.game);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel.Review);
}
private Game GetGameById(int gameId)
{
return db.Games.First(g => g.Id == gameId);
}
private void UpdateGamePlatforms(Game game, IList<Platform> selectedPlatforms)
{
var gamePlatforms = game.Platforms.ToList();
foreach (var gamePlatform in gamePlatforms)
{
if (selectedPlatforms.Contains(gamePlatform) == false)
{
game.Platforms.Remove(gamePlatform);
}
else
{
selectedPlatforms.Remove(gamePlatform);
}
}
game.Platforms.AddRange(selectedPlatforms);
}
在我的 POST 编辑功能中,我的视图模型包含我要更新的游戏和我要添加到游戏中的平台 ID 列表。
使用此代码,我能够将平台添加到我的游戏中,但无法删除它们。我在末尾放置了一个断点,肯定会看到 viewModel.Game.Platforms 只有我选择的内容,但它没有在我的游戏列表中更新。
如果我添加几个平台并同时删除一些。添加了新平台,但删除了 none。
public ActionResult Edit(GameViewModel viewModel)
{
if (ModelState.IsValid)
{
List<Platform> platforms = new List<Platform>();
foreach (var id in viewModel.PostedPlatforms.PlatformIds)
{
platforms.Add(db.Platforms.Find(Int32.Parse(id)));
}
db.Games.Attach(viewModel.Game);
viewModel.Game.Platforms = platforms;
db.Entry(viewModel.Game).State = EntityState.Modified;
UpdateModel(viewModel.Game);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel.Game);
}
型号class是
public class Game
{
public int GameId { get; set; }
public string Title { get; set; }
public List<Platform> Platforms { get; set; }
}
public class Platform
{
public int PlatformId { get; set; }
public string Name { get; set; }
public List<Game> Games { get; set; }
}
根据 ourmandave 的建议,我得到了这段代码,虽然它确实改变了平台选择,但它每次都会创建一个新的游戏入口,这很低效,而且还会增加内容的 id,这会弄乱书签。
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(GameViewModel viewModel)
{
if (ModelState.IsValid)
{
List<Platform> platforms = new List<Platform>();
if(viewModel.PostedPlatforms != null)
{
foreach (var id in viewModel.PostedPlatforms.PlatformIds)
{
platforms.Add(db.Platforms.Find(Int32.Parse(id)));
}
}
db.Games.Remove(db.Games.Find(viewModel.Game.PostId));
db.SaveChanges();
viewModel.Game.Platforms = platforms;
db.Games.Add(viewModel.Game);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel.Game);
}
你可以试试这个...
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(GameViewModel viewModel)
{
if (ModelState.IsValid)
{
List<Platform> selectedPlatforms = viewModel.Select(pl => GetPlatformById(pl.Id)).ToList();
var game = GetGameById(viewModel.Id);
UpdateGamePlatforms(game, selectedPlatforms);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel.Game);
}
private Platform GetPlatformById(int platformId)
{
return db.Platforms.First(pl => pl.Id == platformId);
}
private Game GetGameById(int gameId)
{
return db.Games.First(g => g.Id == gameId);
}
private void UpdateGamePlatforms(Game game, IList<Platform> selectedPlatforms)
{
var gamePlatforms = game.Platforms.ToList();
foreach (var gamePlatform in gamePlatforms)
{
if (selectedPlatforms.Contains(gamePlatform) == false)
{
game.Platforms.Remove(gamePlatform);
}
else
{
selectedPlatforms.Remove(gamePlatform);
}
}
game.Platforms.AddRange(selectedPlatforms);
}
UpdateGamePlatforms
将从游戏中删除不再选择的平台。它将保留仍处于选中状态的平台,并且还会向已选中的游戏添加新平台。
解决方案:使用 TomJerrum 的解决方案,我现在可以正确编辑平台列表。要更新其余属性,我必须映射我尝试编辑的游戏对象的所有 属性 以匹配我的 viewModel 的 属性。值得庆幸的是,已经有一个功能,所以我只需要添加 db.Entry(game).CurrentValues.SetValues(viewModel.game);.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(GameViewModel viewModel)
{
if (ModelState.IsValid)
{
List<Platform> selectedPlatforms = new List<Platform>();
if (viewModel.PostedPlatforms != null)
{
int[] platformIds = Array.ConvertAll(viewModel.PostedPlatforms.PlatformIds, p => Convert.ToInt32(p));
selectedPlatforms.AddRange(db.Platforms.Where(item => platformIds.Contains(item.PlatformId)).ToList());
}
var game = GetGameById(viewModel.Id);
UpdateGamePlatforms(game, selectedPlatforms);
db.Entry(game).CurrentValues.SetValues(viewModel.game);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel.Review);
}
private Game GetGameById(int gameId)
{
return db.Games.First(g => g.Id == gameId);
}
private void UpdateGamePlatforms(Game game, IList<Platform> selectedPlatforms)
{
var gamePlatforms = game.Platforms.ToList();
foreach (var gamePlatform in gamePlatforms)
{
if (selectedPlatforms.Contains(gamePlatform) == false)
{
game.Platforms.Remove(gamePlatform);
}
else
{
selectedPlatforms.Remove(gamePlatform);
}
}
game.Platforms.AddRange(selectedPlatforms);
}