代码之家  ›  专栏  ›  技术社区  ›  Fabricio Rodriguez

使用EF Core 2.1从ASP.Net Core 2.1 Web API向SQL Server数据库插入记录时出错

  •  0
  • Fabricio Rodriguez  · 技术社区  · 8 年前

    我已经创建了一个新的ASP.NETCore2.1WebAPI。它使用EF Core(代码优先)读取和写入sqlserver数据库。所以我使用迁移来生成/构建数据库。

    在控制器中的[HTTPPOST]操作方法上,当它向DbContext添加新记录并尝试保存时,出现以下错误:

    System.Data.SqlClient.SqlException(0x80131904):无法插入 表'Readings'中标识列的显式值 IDENTITY\u INSERT设置为OFF。

    数据库只有一个表:

    USE [eballcoz_mssql]
    GO
    
    /****** Object:  Table [eballcoz_admin].[Readings]    Script Date: 2018/11/08 21:13:34 ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE TABLE [eballcoz_admin].[Readings](
        [Id] [int] IDENTITY(1,1) NOT NULL,
        [BaseId] [int] NULL,
        [Frequency] [int] NULL,
        [Modulation] [int] NULL,
        [Agc1] [int] NULL,
        [Agc2] [int] NULL,
        [TimeStamp] [datetime2](7) NULL,
     CONSTRAINT [PK_Readings] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
    

    我的模型是这样的:

    public class Reading
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public int? BaseId { get; set; }
        public int? Frequency { get; set; }
        public int? Modulation { get; set; }
        public int? Agc1 { get; set; }
        public int? Agc2 { get; set; }
        public DateTime? TimeStamp { get; set; }
    }
    

    我的动作方法是这样的:

        // POST: api/Readings/one
        [HttpPost]
        public async Task<IActionResult> PostReading([FromBody] Reading reading)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
    
            _context.Readings.Add(reading);
            await _context.SaveChangesAsync();
    
            return CreatedAtAction("GetReading", new { id = reading.Id }, reading);
        }
    

    我理解问题所在—我的模型包含“Id”主键字段,因此它试图将其写入数据库表,而SQL Server不喜欢这样。问题是,当我从数据库读取数据时,我需要模型中的“Id”字段。我本以为 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 模型中的decorator会告诉EF它不应该尝试插入Id列,但它似乎不起作用。我也试着用流利的语言来表达:

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Reading>()
            .HasKey(r => r.Id);
    
            modelBuilder.Entity<Reading>()
            .Property(r => r.Id)
            .UseSqlServerIdentityColumn()
            .ValueGeneratedOnAdd();
        }
    

    基本上有两种不同的方法可以插入记录而不会出错: 2) 当IDENTITY\U INSERT设置为ON时。主键“ID”必须存在

    所以我基本上是在尝试解决方案1—我不想提供主键值。我希望SQL Server自动为我生成它。但我的模型确实包含Id列,因为我在从数据库读取时需要它。。。有什么想法吗?

    2 回复  |  直到 8 年前
        1
  •  1
  •   Yepeekai    8 年前

    你应该去reading.Id查一下。将对象添加到dbcontext时,该值必须为0。您可以编辑它以强制: reading.Id = 0;

        2
  •  1
  •   Adam Vincent    8 年前

    实体框架已经处理了您所看到的问题。我相信你的问题在别处。

    EF的默认行为

    当你新建一个属性为的对象时 int ,它的默认值为0。它不是可为null的类型,因此不能为 null . 当该物业 Id 在本例中)标记为自动递增主键,EF Core在 DbContext SaveChanges() 调用,然后EF Core填充

    var reading = new Reading(); //Id = 0
    _context.Add(reading); //Id still 0
    _context.SaveChanges(); //Id = 5 (or whatever Id from SQL
    System.Console.Writeline($"Id: {reading.Id}" //output -> Id: 5
    

    真正的问题是什么?

    当你收到你的 Reading 来自客户机的对象 PostReading 身份证件

    [HttpPost]
    public async Task<IActionResult> PostReading([FromBody] Reading reading)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
    
        //quick debug test
        if (reading.Id > 0) 
        {
           throw new ArgumentException("Something erroneously filled out the Id.");
        }
    
        _context.Readings.Add(reading);
        await _context.SaveChangesAsync();
    
        return CreatedAtAction("GetReading", new { id = reading.Id }, reading);
    }
    
    推荐文章