【发布时间】:2021-10-05 22:34:00
【问题描述】:
我正在尝试从 EF Core 中删除使用 C# 和 DataTables 渲染的 ASP.NET MVC 5 生成的 SQL Server DB。
起初我能够成功删除跨 3 表关系的中间相关表记录。但是在重新启动会话后,我在尝试删除时收到此错误。
> An unhandled exception occurred while processing the request.
> DbUpdateConcurrencyException: Database operation expected to affect 1
> row(s) but actually affected 0 row(s). Data may have been modified or
> deleted since entities were loaded. See
> http://go.microsoft.com/fwlink/?LinkId=527962 for information on
> understanding and handling optimistic concurrency exceptions.
这些是我正在使用的表格。我正在尝试删除注册实体中的记录。
我检查了当我跨过代码时是否在后端发生了删除,但是当我在方法 UnassignUserRegistration(int RegistrationID) 中的这一行时,结果没有发送到数据库。
await _context.SaveChangesAsync();
我现在将向您展示我的代码。如果您需要我显示任何相关代码来帮助解决问题,或者我是否在与问题无关的代码中添加了太多内容,请告诉我,谢谢。
更新:21 年 3 月 8 日为 User 和 Job 以及 TeamContext 添加了模型。
JobController.cs
public IActionResult GetAssignedUsers()
{
_context.Jobs.OrderByDescending(j => j.ID).FirstOrDefault();
var userlist = _context.Users.Where(u => u.Registrations.Any());
return Json(userlist);
}
/// <summary>
/// Opens up the UserAssignments view page, using the
/// currently selected JobID in memory.
/// </summary>
/// <param name="ID"></param>
/// <returns>The currently selected Job in memory</returns>
public IActionResult UserAssignments(int? ID)
{
if (ID == null)
{
return NotFound();
}
var job = _context.Jobs.Find(ID);
return View(job);
}
//TO DO: Fix method.
[HttpGet]
public async Task<IActionResult> UnassignUserRegistration(int RegistrationID)
{
Registration registration = new Registration{ID = RegistrationID};
_context.Registrations.Remove(registration).State = EntityState.Deleted;
await _context.SaveChangesAsync();
return RedirectToAction(nameof(UserAssignments), new{ID = RegistrationID});
}
注册模式
using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace Pitcher.Models
{
public class Registration
{
public int ID {get;set;}
public int UserID { get; set; }
public int JobID { get; set; }
[Required]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "User Start Date")]
[Column("RegistrationDate")]
public DateTime RegistrationDate {get;set;}
public User User {get;set;}
public Job Job {get;set;}
}
}
工作模式
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace Pitcher.Models
{
public class Job
{
public int ID { get; set; }
[Required]
[StringLength(20, MinimumLength = 3, ErrorMessage = "Job Title must be bettween 3 to 20 characters.")]
[DataType(DataType.Text)]
[Display(Name = "Job Title")]
[Column("JobTitle")]
public string JobTitle { get; set; }
[StringLength(200, MinimumLength = 3, ErrorMessage = "Job Description must be bettween 200 to 3 characters.")]
[DataType(DataType.Text)]
[Display(Name = "Description")]
[Column("JobDescription")]
public string JobDescription { get; set; }
[Required]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = " Start Date")]
[Column("JobStartDate")]
public DateTime JobStartDate {get;set;}
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Deadline Date")]
[Column("JobDeadlineDate")]
public DateTime JobDeadline {get;set;}
[Display(Name = "Job Is Complete?")]
[Column("JobIsComplete")]
public bool JobIsComplete{get;set;}
public ICollection<Registration> Registrations {get;set;}
public ICollection<Result> Results {get;set;}
}
}
用户模型
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Pitcher.Models;
namespace Pitcher.Models
{
public class User
{
public int ID { get; set; }
[Required]
[StringLength(20, MinimumLength = 2, ErrorMessage = "* First Name be bettween 2 to 20 characters.")]
[DataType(DataType.Text)]
[Display(Name = "First Name")]
[Column("UserFirstName")]
public string UserFirstName { get; set; }
[Required]
[StringLength(30, MinimumLength = 2, ErrorMessage = "* Last Name be bettween 2 to 30 characters.")]
[DataType(DataType.Text)]
[Display(Name = "Last Name")]
[Column("UserLastName")]
public string UserLastName { get; set; }
[Required]
[StringLength(30, MinimumLength = 3, ErrorMessage = "Email address must be bettween 3 to 30 characters.")]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email")]
[Column("UserContactEmail")]
public string UserContactEmail{get;set;}
// [Required(AllowEmptyStrings = true)]
[Display(Name = "Phone Number")]
[Phone()]
[Column("UserPhoneNumber")]
public string UserPhoneNumber{get;set;}
[StringLength(37,ErrorMessage = "Address cannot be longer than 37 characters.")]
[DataType(DataType.Text)]
[Display(Name = "Address")]
[Column("UserAddress")]
public string UserAddress{get;set;}
//This regular expression allows valid postcodes and not just USA Zip codes.
[Display(Name = "Post Code")]
[Column("UserPostCode")][DataType(DataType.PostalCode)]
public string UserPostCode { get; set; }
[StringLength(15,ErrorMessage = "Country cannot be longer than 15 characters.")]
[DataType(DataType.Text)]
[Display(Name = "Country")]
[Column("UserCountry")]
public string UserCountry {get;set;}
[Phone()]
[Display(Name = "Mobile Number")]
[Column("UserMobileNumber")]
public string UserMobileNumber {get;set;}
[StringLength(3,ErrorMessage = "State cannot be longer than 3 characters.")]
[DataType(DataType.Text)]
[Display(Name = "State")]
[Column("UserState")]
public string UserState {get;set;}
public string UserFullname => string.Format("{0} {1}", UserFirstName, UserLastName);
public ICollection<Registration> Registrations {get;set;}
}
}
团队上下文
using Pitcher.Models;
using Microsoft.EntityFrameworkCore;
using Pitcher.Models.TeamViewModels;
namespace Pitcher.Data
{
public class TeamContext : DbContext
{
public TeamContext(DbContextOptions<TeamContext> options) : base(options)
{
}
public DbSet<User> Users { get; set; }
public DbSet<Registration> Registrations {get;set;}
public DbSet<Job> Jobs {get;set;}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().ToTable("tblUser");
modelBuilder.Entity<Registration>().ToTable("tblRegistration");
modelBuilder.Entity<Job>().ToTable("tblJob");
}
}
}
UserAssignments.cshtml 查看表格代码
<h3>Assigned Users</h3>
<table id="registeredUsersTable" style="display: none">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => user.UserFirstName)
</th>
<th>
@Html.DisplayNameFor(model => user.UserLastName)
</th>
<th>
@Html.DisplayNameFor(model => user.UserContactEmail)
</th>
<th>
</th>
</tr>
</thead>
@if(user == null)
{
<script type="text/javascript">
alert("Model empty");
</script>
}
else
{
<tbody></tbody>
}
</table>
document.getElementById('registeredUsersTable').style.display = 'block';
var id=@Model.ID
$('#registeredUsersTable').DataTable({
"ajax": {
'type': 'get',
'data': { ID: id},
'dataType': "json",
"url": "@Url.Action("GetAssignedUsers")",
"dataSrc": function (result) {
return result;
}
},
"columns": [
{ "data": "userFirstName"},
{ "data": "userLastName"},
{ "data": "userContactEmail"},
{
"data": null,
"render": function (value) {
return '<a href="/Jobs/UnassignUserRegistration?RegistrationID=' + value.id + '"button type="button" class="btn btn-primary btn-block">Unassign</a>';
}
}
]
});
【问题讨论】:
-
这是一个多对多关系,而不是
middle entity,修改它不会导致并发冲突。您编写的代码并没有 删除实体,它附加了一个仅包含部分数据的新对象。当 EF 尝试保存它时,它会检测到数据不匹配并假设存在并发冲突。如果您想避免加载实体,不要使用 EF。否则你必须加载实体并删除它
标签: c# sql-server asp.net-core datatables entity-framework-core