【发布时间】:2022-01-06 04:27:50
【问题描述】:
我正在尝试创建一个项目可以有多个用户的项目项。您可以通过输入用户的姓名并按下按钮来分配用户;控制器将找到用户并返回用户(如果存在)。然后将它们添加到列表中,然后在项目创建提交时将其分配给项目。当项目使用 POST 时,SaveChangesAsync() 会产生一个带有错误的 http 响应 500:
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
---> Microsoft.Data.SqlClient.SqlException (0x80131904): Violation of PRIMARY KEY constraint 'PK_AspNetUsers'. Cannot insert duplicate key in object 'dbo.AspNetUsers'. The duplicate key value is (fa2f3cdf-6147-4973-9c1e-988a21408610).
The statement has been terminated.
我似乎无法弄清楚为什么会发生这种情况,我觉得表单被提交了两次,或者通过两个按钮错误地提交了 Editform。我对 Blazor 和 EF 非常陌生,因此我希望能深入了解可能导致此问题的原因以及如何解决此问题。提前致谢
创建剃须刀页面
<EditForm Model="@projectItem" OnValidSubmit="@CreateNewProject">
<DataAnnotationsValidator />
<div class="form-group">
<label class="custom-control-label"> Name </label>
<InputText id="title" @bind-Value="projectItem.ProjectName" class="form-control" />
<InputText id="title" @bind-Value="projectItem.ProjectDescription" class="form-control" />
<ValidationMessage For="@(() => projectItem.ProjectName)" />
<button type="submit" class="btn btn-primary">Create Project</button>
</div>
<ValidationSummary />
</EditForm>
<EditForm Model="@AssignUser" OnValidSubmit="@AddUserToProject">
<DataAnnotationsValidator />
<div class="form-group">
<label class="custom-control-label"> Assign users </label>
<InputText id="title" type="email" @bind-Value="@AssignUser.UserName" class="form-control" />
<button type="submit" class="btn btn-primary">Add User</button>
</div>
</EditForm>
<p> Currently assigned users </p>
@if (ListOfAllUsers.Count() == 0)
{
<p> No users assigned yet</p>
}
else
{
@for(int i = 0; i < ListOfAllUsers.Count(); i++)
{
<li> @ListOfAllUsers[i].UserName </li>
}
}
private Project projectItem { get; set; } = new Project();
private ApplicationUser AssignUser { get; set; } = new ApplicationUser();
private List<ApplicationUser> ListOfAllUsers { get; set; } = new List<ApplicationUser>();
//submit and create project with the assigned users
private async void CreateNewProject()
{
projectItem.AssignedUsersToProject = ListOfAllUsers;
try
{
var response = await Http.PostAsJsonAsync("Projects", projectItem);
var content = await response.Content.ReadAsStringAsync();
var project = JsonConvert.DeserializeObject<Project>(content);
if(response.IsSuccessStatusCode)
Navigation.NavigateTo($"/projects");
}
catch (Exception e)
{
}
}
// find and add user
private async void AddUserToProject()
{
try
{
var response = await Http.PostAsJsonAsync($"Projects/{AssignUser.UserName}", AssignUser);
var content = await response.Content.ReadAsStringAsync();
var userobject = JsonConvert.DeserializeObject<ApplicationUser>(content);
if (response.IsSuccessStatusCode)
{
if (!ListOfAllUsers.Any(n => n.UserName.Equals(userobject.UserName)))
{
ListOfAllUsers.Add(userobject);
} else
{
AssignUser.UserName = "This user is already added to the project.";
}
} else if (!response.IsSuccessStatusCode)
{
AssignUser.UserName = "User not found, try again";
}
}
catch (Exception e)
{
}
}
控制器:创建项目
[HttpPost]
public async Task<ActionResult<Project>> PostProject(Project project)
{
_context.Projects.Add(project);
await _context.SaveChangesAsync(); // error occurs when reaching this point
return CreatedAtAction("GetProject", new { id = project.ProjectId }, project);
}
控制器:查找并返回用户
[HttpPost("{userEmail}")]
public async Task<ActionResult<ApplicationUser>> AddUserToProject(string userEmail)
{
try
{
// Find user
ApplicationUser userValid = _userManager.Users.Where
(s => s.Email == userEmail).First();
return userValid;
}
catch (InvalidOperationException)
{
return BadRequest();
}
}
型号
public class Project
{
[Key]
public Guid ProjectId { get; set; }
[Required]
public string ProjectName { get; set; }
[JsonIgnore]
public ICollection<ApplicationUser> AssignedUsersToProject { get; set; }
public Company assignedCompanyForProject { get; set; }
}
public class ApplicationUser : IdentityUser
{
public string firstName { get; set; }
public string lastName { get; set; }
[JsonIgnore]
public ICollection<Project> Projects { get; set; }
}
表格图片
您键入要添加到项目中的用户的名称,然后单击“添加用户”,如果用户是存在的用户,它将查找并返回用户(这不会创建项目,但只会查找用户)。然后将该用户添加到 ListOfAllUsers 列表中,然后循环显示所有当前分配的用户。一旦在相关用户旁边给出了项目标题和描述,应按下“创建项目”按钮,这将使用已确定的分配用户创建整个项目。这是提交到数据库以添加新项目项的内容
建议的更改
实现 EntityState.Unchanged;
foreach(var x in project.AssignedUsersToProject)
{
_context.Entry(x).State = EntityState.Unchanged;
}
_context.Projects.Add(project);
导致以下错误:
ystem.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32
【问题讨论】:
-
如果在现有项目中添加一个新用户,它基本上是用新用户创建一个全新的项目吗?因为您似乎只使用
.Add。或者这是否会使用新用户更新现有项目?我的猜测是您正在尝试添加您拥有现有用户的现有项目的副本。如果您尝试添加与该用户相同的项目,它会抱怨有 2 个用户使用相同的密钥。因此,您要么只更新项目并忽略现有用户。或者您必须完全覆盖/删除当前项目,然后注入新项目。 -
表单的工作方式是您输入要添加的用户名,然后将用户添加到列表中。您可以不断重复此过程来添加用户。要与您选择的这些用户确认项目创建,请单击“创建项目”按钮,该按钮应与相关用户一起提交新项目项。我将添加表单的图像,这可能更容易可视化
-
@HenkHolterman 在上述多对多关系的情况下,如果我将子对象的状态设置为 Detached,这会破坏 EF 自动生成的第三个表关系吗?
-
@HenkHolterman 我已经进行了您建议的更改,但是由于这样做,我似乎遇到了另一个错误。我已经更新了底部的帖子以显示我实现的代码和我得到的错误
-
感谢@HenkHolterman 的帮助
标签: asp.net-core entity-framework-core asp.net-identity blazor