Entity Framework Core 中无法更新自增列身份标识。

26

我已经在AspNetUsers表中添加了一个名为NumericId的单独标识,它将与ASP默认的GUID ID一起使用。

我已将该属性添加为ApplicationUser类的附加属性:

public class ApplicationUser : IdentityUser
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public virtual int NumericId { get; set; }
}

然而,当我尝试注册或更新用户的详细信息(这与numericId无关)时,我一直收到错误提示。

SqlException: Cannot update identity column 'NumericId'.

它防止任何更改,并最终不更新用户(但它确实注册一个,且数字ID在该部分上被正确分配。但这是无关紧要的)


你是否正在使用Fluent API?在OnModelCreating方法中有对NumericId的处理吗? - Sanket
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - DethoRhyne
看起来像是个 bug。EF 正试图将一个值插入到由数据库自动生成的列中。你能否提交一个新的问题 - bricelam
从技术上讲,它甚至不应该进行插入。该值已设置并调用的方法应该只是“更新”。我可以尝试将属性设置为空,也许那样它就会忽略它,但我担心这样做会造成一些损害。 - DethoRhyne
缺失:抛出异常的实际代码。 - Gert Arnold
11个回答

24

ASP.NET Core 3.1的解决方案

modelBuilder.Entity<Type>().Property(u => u.Property).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);

1
我可以确认这个方法是可行的,但在脚手架更新自定义问题得到解决之前,这个解决方案会被清除,并且每次需要从数据库首先更新模型时都必须重新输入。也许更好的方法是创建一个单独的类来使用它,而不是直接将其放置在dbContext文件中。 - mighty_mite
@mighty_mite 是的,你说得对。但我是用这种方法进行代码优先的处理。 - HO3EiN
这也解决了我的一个问题。但是我不明白为什么特定的实体需要这个?我的代码中只有一个实体似乎需要这行代码 - 所有其他实体都可以正常更新而无需它? - Raj
1
谢谢 @HO3EiN,在Core 3.1的Code first方法中对我有用。 - Pradip Rupareliya

15
根据GitHub上讨论此问题的讨论,对于EF Core 2.0,我们需要使用其他帖子中建议的两行代码。引用块如下:

对于Entity Framework Core 2.0,"IsReadOnlyAfterSave"属性已被弃用。使用以下内容:

builder.Property(p => p.Id)
    .UseSqlServerIdentityColumn();

builder.Property(p => p.Id)
    .Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;

8
我发现了另一种解决方案(我正在使用.NET Core 2.1):
using System;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using YetAnotherERP.Data;
using YetAnotherERP.Entities;
using YetAnotherERP.Exceptions;
using YetAnotherERP.Utils;

namespace YetAnotherERP.Services
{
    public class EmployeeRepository : IEmployeeRepository
    {

    private DataContext _context;

    public EmployeeRepository(DataContext dataContext)
    {
        _context = dataContext;
    }


    ....


            public async Task UpdateEmployee(Employee employee)
        {
            _context.Update(employee).Property(x=>x.Id).IsModified = false;
            _context.SaveChanges();
        }

8
如果您正在使用 EF Core 2.1,您可以尝试这个。
builder.Property(e => e.ColumnName).Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;

这对我很有用。

IsReadOnlyAfterSave已被弃用。


8
这是EF Core 1.0的一个错误。请参见EF尝试插入身份字段。EF Core 1.2已将该问题标记为已修复,但不更新的解决方法是使用。
modelBuilder.Entity<Type>().Property(u => u.Property).UseSqlServerIdentityColumn();

2
https://dev59.com/X6rka4cB1Zd3GeqPdnLf - user8280126

3

asp.net core 5 EF 5 的解决方案

modelBuilder.Entity<Type>().Property(u => u.Property).ValueGeneratedOnUpdate().Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);

ValueGeneratedOnUpdate 意为在更新时生成值。SetAfterSaveBehavior(PropertySaveBehavior.Ignore) 意味着什么都不做。 - Gert Arnold

2

这行代码解决了我的问题。 从1.1.1版本开始可用。

modelBuilder.Entity<ApplicationUser>().Property(u => u.NumberId).Metadata.IsReadOnlyAfterSave = true;

1

根据GitHub上的讨论这里,关键(双关语)是将属性标记为备用键,因此在后续更新中,EF Core不会尝试为只读的基础标识列设置值。

在幕后,它可能与其他答案执行相同的操作,但这是修复它的语义正确的方式。

流畅式配置:

entityTypeBuilder.HasAlternateKey(e => e.NumericId);

0
实际上,这是由于实体框架自身创建了主键引起的,尽管我们在userIdentity中有一个Id列。我在DBContext的onModelCreation函数中解决了这个问题。
       base.OnModelCreating(modelBuilder);

0
在我的情况下(核心3.1),我注意到我错误地标识了另一列,当我将真实的列标记为键时,问题得到解决。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接