【发布时间】:2021-03-27 20:39:04
【问题描述】:
这是我在堆栈上的第一篇文章,很抱歉给您带来不便或我的英语不好。
我在 Entity Framework SaveChanges() 向数据库表中添加新的 User 记录两次时遇到问题。
我创建了一个UserFormViewModel,用于根据来自模态窗口表单的用户输入发布数据。
这是我的UserFormViewModel:
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Username { get; set; }
[Required]
[StringLength(20)]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[Required]
[StringLength(50)]
public string Surname { get; set; }
[Required]
[StringLength(255)]
[EmailAddress]
public string Email { get; set; }
public byte UserRoleId { get; set; }
public Address Address { get; set; }
public IEnumerable<UserRole> UserRoles { get; set; }
来自视图的所有输入都正确映射到AddOrEdit 操作方法参数,因此当通过SaveChanges() 方法将数据保存到数据库时出现问题。它在表中添加了两次记录。
- 我尝试单独添加
User,它添加了两次User。 - 然后我尝试单独添加
Address,它添加了两次Address。 - 在一个
dbContext实例或两个分开的dbContext实例中保存User和Address时,User和Address会再次添加两次。
也尝试了数据库优先方法,但结果相同。
我假设它与表之间的关系有关,但无法指出正确的原因。
在Address 模型类中有街道地址的标准属性:
Id, StreetName, StreetNumber, Zip, City
还有两个外键:
public int? UserId { get; set; }
public int? ShopId { get; set; }
public virtual User User { get; set; }
public virtual Shop Shop { get; set; }
所以User 和Shop 共享Address 表以获取他们的地址。
当User 和Shop 设置为引用Address 表时,另一种方法都可以正常工作。
但我想了解为什么这不起作用并最终使 Address 能够级联 User 或 Shop 删除而不是使用 LINQ 删除 Address。
这是AddOrEdit 的操作方法User 及其Address:
private readonly FurnitureStoreDbContext _context;
public UsersController()
{
_context = new FurnitureStoreDbContext();
}
protected override void Dispose(bool disposing)
{
_context.Dispose();
}
[HttpPost]
public ActionResult AddOrEdit(UserFormViewModel userForm)
{
if (userForm.Id == 0)
{
var newUser = new User
{
Username = userForm.Username,
Password = userForm.Password,
Name = userForm.Name,
Surname = userForm.Surname,
Email = userForm.Email,
UserRoleId = userForm.UserRoleId
};
_context.tblUsers.Add(newUser);
_context.SaveChanges();
var newAddress = new Address
{
StreetName = userForm.Address.StreetName,
StreetNumber = userForm.Address.StreetNumber,
ZipCode = userForm.Address.ZipCode,
City = userForm.Address.City,
UserId = newUser.Id
};
_context.tblStreetAddresses.Add(newAddress);
_context.SaveChanges();
return Json(new { success = true, message = "Saved" }, JsonRequestBehavior.AllowGet);
}
else
{
var updatedUser = new User
{
Username = userForm.Username,
Password = userForm.Password,
Name = userForm.Name,
Surname = userForm.Surname,
Email = userForm.Email,
UserRoleId = userForm.UserRoleId
};
var updatedAddress = userForm.Address;
_context.Entry(updatedUser).State = EntityState.Modified;
_context.SaveChanges();
_context.Entry(updatedAddress).State = EntityState.Modified;
_context.SaveChanges();
return Json(new { success = true, message = "Updated" }, JsonRequestBehavior.AllowGet);
}
}
这是一个调试日志,只添加User - 不添加Address。
Violation of UNIQUE KEY constraint 'UQ__Users__536C85E479927847' 发生异常,因为我已将 Username 字段设置为唯一且上下文尝试添加 User 记录两次。
Step into: Stepping over property 'FurnitureStore.Models.User.get_Addresses'. To step into properties or operators, go to Tools->Options->Debugging and uncheck 'Step over properties and operators (Managed only)'.
Step into: Stepping over property 'FurnitureStore.Models.User.get_Addresses'. To step into properties or operators, go to Tools->Options->Debugging and uncheck 'Step over properties and operators (Managed only)'.
Opened connection at 3/27/2021 8:55:09 PM +01:00
Opened connection at 3/27/2021 8:55:09 PM +01:00
Started transaction at 3/27/2021 8:55:09 PM +01:00
Started transaction at 3/27/2021 8:55:09 PM +01:00
INSERT [dbo].[Users]([Username], [Password], [Name], [Surname], [Email], [UserRoleId])
VALUES (@0, @1, @2, @3, @4, @5)
SELECT [Id]
FROM [dbo].[Users]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()INSERT [dbo].[Users]([Username], [Password], [Name], [Surname], [Email], [UserRoleId])
VALUES (@0, @1, @2, @3, @4, @5)
SELECT [Id]
FROM [dbo].[Users]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()
-- @0: 'Username 1' (Type = String, Size = 50)
-- @0: 'Username 1' (Type = String, Size = 50)
-- @1: 'q1w2e3r4' (Type = String, Size = 20)
-- @2: 'Name 1' (Type = String, Size = 50)
-- @3: 'Surname 1' (Type = String, Size = 50)
-- @4: 'jjee@gmail.com' (Type = String, Size = 255)
-- @5: '2' (Type = Byte, Size = 1)
-- Executing at 3/27/2021 8:55:10 PM +01:00
-- @1: 'q1w2e3r4' (Type = String, Size = 20)
-- @2: 'Name 1' (Type = String, Size = 50)
-- @3: 'Surname 1' (Type = String, Size = 50)
-- @4: 'jjee@gmail.com' (Type = String, Size = 255)
-- Completed in 7 ms with result: SqlDataReader
-- @5: '2' (Type = Byte, Size = 1)
-- Executing at 3/27/2021 8:55:10 PM +01:00
Committed transaction at 3/27/2021 8:55:10 PM +01:00
-- Failed in 26 ms with error: Violation of UNIQUE KEY constraint 'UQ__Users__536C85E479927847'. Cannot insert duplicate key in object 'dbo.Users'. The duplicate key value is (Username 1).
The statement has been terminated.
Closed connection at 3/27/2021 8:55:10 PM +01:00
Closed connection at 3/27/2021 8:55:10 PM +01:00
Exception thrown: 'System.Data.Entity.Infrastructure.DbUpdateException' in EntityFramework.dll
An exception of type 'System.Data.Entity.Infrastructure.DbUpdateException' occurred in EntityFramework.dll but was not handled in user code
An error occurred while updating the entries. See the inner exception for details.
The thread 0x42cc has exited with code 0 (0x0).
感谢任何帮助。
谢谢:)
【问题讨论】:
-
该代码看起来不错。您可能正在运行控制器两次,或者您的数据库中已经有该用户。而且您在“更新”分支上遇到了一个错误,因为您在尝试更新之前没有在实体上设置用户 ID。
-
updatedUser没有设置Id值(而数据库表显然有该字段)。这应该会导致更新问题,但不会重新插入您的编码方式。
标签: asp.net-mvc entity-framework