可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm using Identity Core 1.0 with ASP.NET MVC Core 1.0 and Entity Framework Core 1.0 to create a simple user registration system with this article as a starting point, and I am trying to add user roles. I can add user roles, but I'm unable to edit them. Here is the Edit
action in the 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();
}
}
Here is the form in the corresponding 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" />
}
The new role name does not save to the database, and I get the following exception: 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.
I was able to use this exact code (with the Microsoft.AspNet.Identity.EntityFramework
dependency instead of EntityFrameworkCore
) to edit database entries using EF 7, Identity 3, etc.
Any thoughts on why this code will not allow database entries to be modified?
回答1:
Unless there is a hidden exception that is hiding behind this as a dumb random exception, the reason is clearly stated in the exception.
Check the Id
on the role
object as you receive it on your Edit
action and try to lookup that id in the database. The exception message you see states that, it is expecting to find a row with a matching Id of the object you attached, but it is not, so it is failing to do the update, since it could not locate a matching row to update it.
EDIT :
You are attaching the entity twice, remove the call to .Attach(role)
and keep the line below it which is sufficient to add the object to the tracking context in a modified state.
//_db.Roles.Attach(role); //REMOVE THIS LINE !.
_db.Entry(role).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
Beware that setting the state of the entry to modified will update all the property values upon calling .SaveChanges()
, so in case you want to update only certain properties refer to this answer.
If this doesn't solve your problem, please check for any inner exceptions that you might've missed. Sometimes the exception messages don't make sense and mask the real problem which you might be able to find in the inner exception.
回答2:
You can try as shown below.
[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();
}
}
Note :
When _db.Entry(role).State = EntityState.Modified;
- you are not only attaching the entity to the
_db
, you are also marking the
whole entity as dirty
.
- When you do
_db.SaveChanges()
, EF will generate an update
statement that will update all the fields of the entity
.
When _db.Roles.Attach(role)
- attaches the entity to the context without marking it dirty.
- It is like
_db.Entry(role).State = EntityState.Unchanged;
.
- unless you then proceed to
update a property on the entity
, the next time you call context.SaveChanges()
, EF
will not generate a database update
for this entity
.
i.e. If you need to generate a database update,you have to do like this :
_db.Roles.Attach(role); // State = Unchanged
role.RoleName = "Admin"; // State = Modified, and only the RoleName property is dirty
context.SaveChanges();
回答3:
After executing the Update or Delete, EF Core reads the number of rows that were affected.
SELECT [ExampleEntityId]
FROM [ExampleEntities]
WHERE @@ROWCOUNT = 1 AND
[ExampleEntityId] = scope_identity();
If your entities do not have IdentityColumn thats primary key, EF Core throws DbUpdateConcurrencyException.
In my case I added primary keys(and set them as identity) to related tables in database.
回答4:
Your answers doesn't work for me. And I solved my error like this.
Changed Model class proporties
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
after ı changed My mapping class
builder.Property(c => c.Id).HasColumnName("ID").IsRequired();
Last change is
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;
I hope This solution works for someone.
回答5:
I have solved this by combining the two methods
var thisRole = _db.Roles.Where(r => r.Id.Equals(role.Id,
StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
_db.Roles.Attach(thisRole);
thisRole.Name = role.Name;
_db.SaveChanges();
回答6:
If you have a Trigger INSTEAD OF INSERT on the table, the Database cancel the operation and EntityFramework fire this error.
回答7:
Same error here, what ended up being the issue is I'm inserting while reusing the code for updating ...
Role role = new Role();
role.Value = input;
context.Add(role);
await context.SaveChangesAsync();
There's no state to be changed when inserting ...
回答8:
in mysql ,it needs a AUTO_INCREMENT ID
like this:
ALTER TABLE wfdbcore201test
.wftransitioninstance
MODIFY COLUMN ID
int(11) NOT NULL AUTO_INCREMENT FIRST;