I am trying to create a new record in my Game
table using EF Core Code First. It shares one-to-many relationships with Genre
, Developer
, Publisher
and Platform
.
I am using a view model called GameCreateViewModel
for the Game/Create View which holds a Game
property as well as properties for select lists that correspond with each foreign key e.g. List<SelectListItem> Genres
.
The problem I am having is when I attempt to create a new Game
, it gives me this error:
Microsoft.EntityFrameworkCore.DbUpdateException
HResult=0x80131500
Message=An error occurred while updating the entries. See the inner exception for details.
Source=Microsoft.EntityFrameworkCore.Relational
StackTrace:
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChanges(IList`1 entries)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IList`1 entriesToSave)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(DbContext _, Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges()
at GameSource.Data.Repositories.GameRepository.Insert(Game game) in E:\Tom\source\repos\My Projects\GameSource\GameSource.Data\Repositories\GameRepository.cs:line 35
at GameSource.Services.GameService.Insert(Game game) in E:\Tom\source\repos\My Projects\GameSource\GameSource.Services\GameService.cs:line 29
at GameSource.Controllers.GamesController.Create(GameCreateViewModel viewModel) in E:\Tom\source\repos\My Projects\GameSource\GameSource\Controllers\GamesController.cs:line 88
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
This exception was originally thrown at this call stack:
[External Code]
Inner Exception 1:
SqlException: Cannot insert explicit value for identity column in table 'Developer' when IDENTITY_INSERT is set to OFF.
Cannot insert explicit value for identity column in table 'Genre' when IDENTITY_INSERT is set to OFF.
Cannot insert explicit value for identity column in table 'Platform' when IDENTITY_INSERT is set to OFF.
Cannot insert explicit value for identity column in table 'Publisher' when IDENTITY_INSERT is set to OFF.
Game model class:
public class Game
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public Genre Genre { get; set; }
public Developer Developer { get; set; }
public Publisher Publisher { get; set; }
public string Description { get; set; }
public Platform Platform { get; set; }
}
Genre model class:
public class Genre
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
}
GameCreateViewModel:
public class GameCreateViewModel
{
public Game Game { get; set; }
public List<SelectListItem> Genres { get; set; }
public List<SelectListItem> Developers { get; set; }
public List<SelectListItem> Publishers { get; set; }
public List<SelectListItem> Platforms { get; set; }
}
Game/Create View - code of Genre select list only, the same format repeated for the other select lists:
@model GameSource.ViewModels.GameViewModel.GameCreateViewModel
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Game.ID" />
<div class="form-group">
<label asp-for="Game.Name" class="control-label"></label>
<input asp-for="Game.Name" class="form-control" />
<span asp-validation-for="Game.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Game.Genre" class="control-label"></label>
<select asp-for="Game.Genre.ID" asp-items="@Model.Genres" class="form-control">
<option value="">Select a Genre/Genres</option>
</select>
<span asp-validation-for="Game.Genre" class="text-danger"></span>
</div>
Game/Create Controller:
[HttpGet]
public IActionResult Create()
{
GameCreateViewModel viewModel = new GameCreateViewModel();
viewModel.Game = new Game();
viewModel.Genres = genreService.GetAll().Select(x => new SelectListItem()
{
Text = x.Name,
Value = x.ID.ToString()
}).ToList();
viewModel.Developers = developerService.GetAll().Select(x => new SelectListItem()
{
Text = x.Name,
Value = x.ID.ToString()
}).ToList();
viewModel.Publishers = publisherService.GetAll().Select(x => new SelectListItem()
{
Text = x.Name,
Value = x.ID.ToString()
}).ToList();
viewModel.Platforms = platformService.GetAll().Select(x => new SelectListItem()
{
Text = x.Name,
Value = x.ID.ToString()
}).ToList();
return View(viewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(GameCreateViewModel viewModel)
{
Game game = new Game
{
ID = viewModel.Game.ID,
Name = viewModel.Game.Name,
Genre = viewModel.Game.Genre,
Developer = viewModel.Game.Developer,
Publisher = viewModel.Game.Publisher,
Description = viewModel.Game.Description,
Platform = viewModel.Game.Platform
};
gameService.Insert(game);
return RedirectToAction("Index");
}
It seems like it is trying to insert a new entry for the foreign keys as well, even though I am simply wanting to use existing IDs for the new Game
entry. E.g. The new Game
has a GenreID of 1, so it should be referring to the existing Genre entry with an ID of 1.
Any insight into this is very much appreciated. Also, please let me know if you need to see the service and repo methods too. Thanks for your time.