![](/img/trans.png)
[英]The INSERT statement conflicted with the FOREIGN KEY using EF Core
[英]EF Core - Unable to insert new entry that has a foreign key
我正在嘗試使用 EF Core Code First 在我的Game
表中創建新記錄。 它與Genre
、 Developer
、 Publisher
和Platform
共享一對多的關系。
我正在使用一個名為GameCreateViewModel
的視圖 model 用於游戲/創建視圖,它包含一個Game
屬性以及與每個外鍵對應的 select 列表的屬性,例如List<SelectListItem> Genres
。
我遇到的問題是當我嘗試創建一個新Game
時,它給了我這個錯誤:
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.
游戲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; }
}
類型model class:
public class Genre
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
}
游戲創建視圖模型:
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; }
}
游戲/創建視圖- 僅類型 select 列表的代碼,其他 select 列表重復相同的格式:
@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>
游戲/創建 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");
}
似乎它也在嘗試為外鍵插入一個新條目,即使我只是想將現有 ID 用於新的Game
條目。 例如,新Game
的 GenreID 為 1,因此它應該引用 ID 為 1 的現有 Genre 條目。
對此的任何見解都非常感謝。 另外,如果您也需要查看服務和回購方法,請告訴我。 謝謝你的時間。
我最終在我的游戲 class 以及我的 GameCreateViewModel 中添加了外鍵的 id 屬性,並重新更新了我的數據庫。 它允許我正確地創建一個新游戲,例如在 controller 中為新游戲分配一個流派時,我能夠根據視圖模型的 Game.GenreID 屬性返回一個流派。
流派示例 - 相同的想法適用於其他外鍵:
游戲創建視圖模型:
public class GameUpdateViewModel
{
public Game Game { get; set; }
public int GenreID { get; set; }
public List<SelectListItem> Genres { get; set; }
游戲/創建 controller 方法:
Game game = new Game
{
ID = viewModel.Game.ID,
Name = viewModel.Game.Name,
Description = viewModel.Game.Description,
GenreID = viewModel.Game.GenreID
在視圖中 - 在 select 列表中,它使用的是 Game.GenreID :
<select asp-for="Game.GenreID" asp-items="@Model.Genres" class="form-control">
<option value="">Select a Genre/Genres</option>
</select>
這個想法是存在外鍵屬性,否則我無法將現有的外鍵 ID 分配給新游戲。
您的游戲實體的表示應該是這樣的:
public class Game
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int GenreId { get; set; }
public int DeveloperId { get; set; }
public int PublisherId { get; set; }
public int PlatformId { get; set; }
public Genre Genre { get; set; }
public Developer Developer { get; set; }
public Publisher Publisher { get; set; }
public Platform Platform { get; set; }
}
由於 EF 跨外鍵引用您的一側實體,因此您應該在您的上下文中配置它。
builder.HasKey(g => g.ID);
builder.Property(g => g.Name);
builder.Property(g => g.Description);
builder.Property(g => g.GenreId).HasColumnName("GenreID");
builder.HasOne(g => g.Genre)
.WithMany(h => h.Games)
.HasForeignKey(g => g.GenreId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_Games_Genre"); // Repeat the last two lines for all your one side entity relationships
現在,當需要添加游戲實體時,您只需放置外鍵。 例如:
new Game({
Name = "GameName"
.
.
GenreId = 1
.
.
});
只需將游戲添加到上下文並保存即可。 EF 將以正確的方式 map 您的實體關系。
注意:請注意您的 EF 可能會有所不同。
如果您是 EF Core 的新手,我建議您在完成 DB 架構后使用 EF Database-First 方法,這將為項目帶來上下文所需的所有配置。
您必須更改代碼
public class Game
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public int GenreID { get; set; }
public int DeveloperID { get; set; }
public int PublisherID { get; set; }
public string Description { get; set; }
public int PlatformID { get; set; }
}
<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="@Model.GameName" class="control-label"></label>
<input asp-for="@Model.GameName" class="form-control" />
<span asp-validation-for="@Model.GameName" class="text-danger"></span>
</div>
<div class="form-group">
<label>Platform</label>
<select asp-for="@Model.PlatformID"
asp-items="@(new SelectList(Model.Platforms,"Id","Name"))">
<option>Please select one</option>
</select>
</div>
<div class="form-group">
<label>Publisher</label>
<select asp-for="@Model.PublisherID"
asp-items="@(new SelectList(Model.Publishers,"Id","Name"))">
<option>Please select one</option>
</select>
</div>
<div class="form-group">
<label>Publisher</label>
<select asp-for="@Model.PublisherID"
asp-items="@(new SelectList(Model.Publishers,"Id","Name"))">
<option>Please select one</option>
</select>
</div>
<div class="form-group">
<label>Developer</label>
<select asp-for="@Model.DeveloperID"
asp-items="@(new SelectList(Model.Developers,"Id","Name"))">
<option>Please select one</option>
</select>
</div>
public class GameCreateViewModel
{
public String GameName { get; set; }
public int GenreID { get; set; }
public int DeveloperID { get; set; }
public int PublisherID { get; set; }
public int PlatformID { get; set; }
public Game Game { get; set; }
public List<Genre> Genres { get; set; }
public List<Developer> Developers { get; set; }
public List<Publisher> Publishers { get; set; }
public List<Platform> Platforms { get; set; }
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(GameCreateViewModel viewModel)
{
Game game = new Game
{
Name = viewModel.GameName,
GenreID = viewModel.GenreID,
DeveloperID = viewModel.DeveloperID,
Publisher = viewModel.PublisherID,
Description = viewModel.Game.Description,
Platform = viewModel.PlatformID
};
gameService.Insert(game);
return RedirectToAction("Index");
}
public class Developer
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
}
public class Publisher
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
}
public class Platform
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.