我正在使用Identity Core 1.0与ASP.NET MVC Core 1.0和Entity Framework Core 1.0创建一个以this article为起点的简单用户注册系统,我正在尝试添加用户角色。我可以添加用户角色,但我无法编辑它们。以下是Edit
中的RolesController
操作:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(IdentityRole role)
{
try
{
_db.Roles.Attach(role);
_db.Entry(role).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception ex)
{
Console.WriteLine(ex);
return View();
}
}
以下是相应视图中的表单:
@model Microsoft.AspNet.Identity.EntityFramework.IdentityRole
@{
ViewBag.Title = "Edit";
}
<h2>Edit Role</h2>
<hr />
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
@Html.HiddenFor(model => model.Id)
<div>Role name</div>
<p>@Html.TextBoxFor(model => model.Name)</p>
<input type="submit" value="Save" />
}
新角色名称未保存到数据库,我收到以下异常: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.
我能够使用这个确切的代码(使用Microsoft.AspNet.Identity.EntityFramework
依赖项而不是EntityFrameworkCore
)来编辑使用EF 7,Identity 3等的数据库条目。
有关为什么此代码不允许修改数据库条目的任何想法?
答案 0 :(得分:3)
除非隐藏的异常隐藏在此作为一个愚蠢的随机异常,否则原因在异常中明确说明。
在您Id
操作中收到role
对象上的Edit
,然后尝试在数据库中查找该ID。您看到的异常消息指出,它期望找到一个与您附加的对象具有匹配ID的行,但它不是,因此它无法执行更新,因为它无法找到匹配的行来更新它
编辑:
您要将实体附加两次,移除对.Attach(role)
的调用并保留其下方的行,这足以将对象添加到处于修改状态的跟踪上下文中。
//_db.Roles.Attach(role); //REMOVE THIS LINE !.
_db.Entry(role).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
请注意,将条目的状态设置为modified将在调用.SaveChanges()
时更新所有属性值,因此,如果您只想更新某些属性,请参阅this answer。
如果这不能解决您的问题,请检查您可能错过的任何内部异常。有时,异常消息没有意义,并掩盖了您可能在内部异常中找到的真正问题。
答案 1 :(得分:1)
您可以尝试如下所示。
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(IdentityRole role)
{
try
{
_db.Entry(role).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception ex)
{
Console.WriteLine(ex);
return View();
}
}
注意:
_db.Entry(role).State = EntityState.Modified;
_db
,还要标记。{
整个实体为dirty
。_db.SaveChanges()
时,EF会生成update
陈述will update all the fields of the entity
。 _db.Roles.Attach(role)
_db.Entry(role).State = EntityState.Unchanged;
。update a property on the entity
,否则下次致电context.SaveChanges()
时,EF
将无法生成 database update
entity
_db.Roles.Attach(role); // State = Unchanged
role.RoleName = "Admin"; // State = Modified, and only the RoleName property is dirty
context.SaveChanges();
1}}。即如果您需要生成数据库更新,则必须执行以下操作:
body{overflow:hidden;}
答案 2 :(得分:1)
您的答案对我不起作用。我这样解决了我的错误。 更改的模型类别比例
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
在我更改了我的映射类之后
builder.Property(c => c.Id).HasColumnName("ID").IsRequired();
最后一次更改是
CustomerEntity thisrole = (from x in db.Customers
where x.Id == Id
select x).First();
thisrole.Id = accountNum;
thisrole.Name = name;
thisrole.Phone = phone;
thisrole.Email = email;
thisrole.Address = address;
db.SaveChanges();
return true;
我希望此解决方案适用于某人。
答案 3 :(得分:1)
如果您尝试更新具有新的相关实体的实体,也会发生这种情况。
someEntity.AnotherEntity = new AnotherEntity();
dbContext.Update(someEntity);
dbContext.SaveChanges(); // Exception
相反,请执行以下操作:
someEntity.AnotherEntity = new AnotherEntity();
dbContext.AnotherEntitySet.Add(someEntity.AnotherEntity);
dbContext.Update(someEntity);
dbContext.SaveChanges(); // No Exception
答案 4 :(得分:0)
我通过结合两种方法解决了这个问题
var thisRole = _db.Roles.Where(r => r.Id.Equals(role.Id,
StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
_db.Roles.Attach(thisRole);
thisRole.Name = role.Name;
_db.SaveChanges();
答案 5 :(得分:0)
如果表上有触发器INSTEAD OF INSERT,则数据库取消操作,并且EntityFramework会引发此错误。
答案 6 :(得分:0)
这里有同样的错误,最终导致的问题是我在重用更新代码时正在插入...
Role role = new Role();
role.Value = input;
context.Add(role);
await context.SaveChangesAsync();
插入时没有状态可以更改...
答案 7 :(得分:0)
执行更新或删除后,EF Core读取受影响的行数。
SELECT [ExampleEntityId]
FROM [ExampleEntities]
WHERE @@ROWCOUNT = 1 AND
[ExampleEntityId] = scope_identity();
如果您的实体没有作为主键的IdentityColumn,则EF Core会引发DbUpdateConcurrencyException。
在我的情况下,我向数据库中的相关表添加了主键(并将它们设置为标识)。
答案 8 :(得分:0)
在mysql中,它需要一个AUTO_INCREMENT ID
像这样:
更改表wfdbcore201test
。wftransitioninstance
修改列ID
int(11)NOT NULL AUTO_INCREMENT FIRST;
答案 9 :(得分:0)
使用Razor Pages时,没有一个可接受的答案对我有用。 我最终使用InputModel Input对其进行了修复。 (我在角色上有自己的课程)。
public class AppRole:IdentityRole<int> { }
[BindProperty]
public InputModel Input { get; set; }
public class InputModel
{
[Required]
public string Name { get; set; }
public string NormalizedName=>Name.ToUpper();
public int Id { get; set; }
// Used to check for concurrency in the post method
public string OriginalConcurrencyStamp { get; set; }
}
通过OnGet方法播种输入。
public IActionResult OnGet(int? id)
{
if (id == null)
{
return NotFound();
}
var appRole = _context.Roles.Find(id);
if(appRole == null) { return NotFound(); }
Input.Id = id.Value;
Input.Name = appRole.Name;
Input.OriginalConcurrencyStamp = appRole.ConcurrencyStamp;
return Page();
}
然后在发布方法中,我“找到”角色并在那里进行更新。
public IActionResult OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var appRole = _context.Roles.Find(Input.Id);
// The role has been deleted
if(appRole == null)
{
ViewData["Error"] = "This Role has been deleted by someone else.\nReturn to the list.";
return Page();
}
// the role has been changed by another user.
if(appRole.ConcurrencyStamp != Input.OriginalConcurrencyStamp)
{
ViewData["Error"] = "This Role has been changed by someone else.\nReturn to the list.";
return Page();
}
// no need to SaveChanges if there are no changes.
var hasChanges = false;
if(appRole.Name != Input.Name)
{
appRole.Name = Input.Name;
hasChanges = true;
}
if(appRole.SortOrder != Input.SortOrder)
{
appRole.SortOrder = Input.SortOrder;
hasChanges = true;
}
if(appRole.NormalizedName != Input.NormalizedName)
{
appRole.NormalizedName = Input.NormalizedName;
hasChanges = true;
}
if(!hasChanges)
{
ViewData["Error"] = "No Changes Detected.";
return Page();
}
appRole.ConcurrencyStamp = Guid.NewGuid().ToString();
_context.Entry(appRole).State = EntityState.Modified;
try
{
_context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
if (!AppRoleExists(Input.Id))
{
return NotFound();
}
else { throw; }
}
return RedirectToPage("./Index");
}
我的Edit.cshtml文件如下所示。
@page
@model MyApp.Areas.Identity.Pages.Account.Manage.Roles.EditModel
@{
ViewData["Title"] = "Edit";
Layout = "~/Pages/Shared/_Layout.cshtml";
}
<h1>Edit</h1>
<h4>Role</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Input.Id" />
<input type="hidden" asp-for="Input.OriginalConcurrencyStamp" />
<label class="text-danger">@ViewData["Error"]</label>
<div class="form-group">
<label asp-for="Input.Name" class="control-label"></label>
<input asp-for="Input.Name" class="form-control" />
<span asp-validation-for="Input.Name" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="./Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
答案 10 :(得分:0)
在我的情况下,问题是我试图从表中删除一个值而不检查该值是否实际存在:
public DbSet<AdminSettings> AdminSettingsTable { get; set; }
public AdminSettings AdminSettings
{
get
{
return AdminSettingsTable.FirstOrDefault();
}
set
{
// This if-statement prevents the crash
if (AdminSettingsTable.Contains(value))
{
AdminSettingsTable.Remove(value);
}
SaveChanges();
AdminSettingsTable.Add(value);
}
}
答案 11 :(得分:0)
我在 delete
操作中遇到此错误。
就我而言,我试图在其他表中删除一行以及与其相关的行(外键关系)。事实证明,如果删除父项,则在数据库中添加了一个触发器以删除相关行。如果要删除,请确保您尝试删除的行存在,或者您是否添加了任何触发器来删除相关的行。
答案 12 :(得分:-1)
对于 SQL Server,EF Core 在 Where 子句中包含时间戳属性,我仍然不明白为什么。所以我必须跟踪主键和时间戳以重新附加实体。
TL;DR:如果您的 Update 语句的 Where 子句中缺少某些内容,请检查您的(EF Core)生成的 SQL。
示例:
实体:
CREATE TABLE [dbo].[Blog]
[BlogID] [int] IDENTITY(0,1) NOT NULL,
[sysTS] [timestamp] NOT NULL,
[IsPublished] [bit] NOT NULL
public class Blog {
public int BlogId { get; set; }
public byte[] SysTS { get; set; }
public bool IsPublished { get; set; }
}
代码:
var blog = new Blog { IsPublished = false };
using(var context = CreateNewContext()) {
context.Blog.Add(blog);
await context.SaveChangesAsync();
}
var blogId = blog.BlogID
// var blogSysTs = blog.SysTs; // this I had to track too
// ... do other stuff
// here also SysTS = blogSysTs was needed
var blog2 = new Blog { BlogID = blogId, IsPublished = true };
using(var context2 = CreateNewContext()) {
var entry = context2.Blog.Attach(blog2);
entry.Property(b => b.IsPublished).IsModified = true;
await context2.SaveChangesAsync();
}
结果如下:
UPDATE Blog
SET IsPublished = @p1
WHERE BlogID = @p2 and SysTS IS NULL
只有在 SysTS 被跟踪的情况下才有合法的更新查询:
UPDATE Blog
SET IsPublished = @p1
WHERE BlogID = @p2 and SysTS = @p3
我知道这肯定与 SQL Server 设置无关,我只是不知道为什么。 但它的要点是:检查您的 EF Core 生成的 SQL 查询以了解该行未更新的原因。