Ошибка при вставке записи в базу данных SQL Server из веб-API ASP .Net Core 2.1 с использованием EF Core 2.1 - PullRequest
0 голосов
/ 08 ноября 2018

Я создал новый веб-API ASP .Net Core 2.1. Он использует EF Core, сначала код, для чтения и записи в базу данных SQL Server. Поэтому я использовал миграции для создания / создания базы данных.

В методе действия [HTTPPOST] в контроллере, когда он добавляет новую запись в DbContext и пытается сохранить, я получаю следующую ошибку:

System.Data.SqlClient.SqlException (0x80131904): невозможно вставить явное значение для столбца идентичности в таблице «Показания», когда Для параметра IDENTITY_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)] в модели скажет EF, что он не должен пытаться вставить столбец Id, но, похоже, он не работает. Я также пытался сделать это в FLUENT:

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

        modelBuilder.Entity<Reading>()
        .Property(r => r.Id)
        .UseSqlServerIdentityColumn()
        .ValueGeneratedOnAdd();
    }

безрезультатно. Как я могу сохранить столбец Id как часть моей модели, но сказать EF не включать его в запрос INSERT? Я прочитал это:

Существует два основных способа вставки записей без ошибок: 1) Когда IDENTITY_INSERT установлен на OFF. ПЕРВИЧНЫЙ КЛЮЧ «ИД» НЕ ДОЛЖЕН БЫТЬ НАСТОЯЩИМ 2) Когда IDENTITY_INSERT включен. ПЕРВИЧНЫЙ КЛЮЧ «ИД» ДОЛЖЕН БЫТЬ НАСТОЯЩИМ

Так что я в основном пытаюсь найти решение № 1 - я не хочу указывать значение первичного ключа. Я хочу, чтобы SQL Server автоматически генерировал его для меня. Но моя модель действительно включает столбец Id, потому что он мне нужен при чтении из базы данных ... Есть идеи?

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

Вы должны проверить при чтении. Ид. Это должно быть 0, когда вы добавляете объект в ваш dbcontext. Вы можете отредактировать его, чтобы заставить: reading.Id = 0;

0 голосов
/ 08 ноября 2018

Entity Framework уже обрабатывает проблему, которую вы смотрите.Я считаю, что ваша проблема кроется в другом месте.

Поведение по умолчанию EF

Когда вы создаете объект со свойством int, его значение по умолчанию равно 0. Это не обнуляемый тип, поэтомуэто не может быть null.Когда это свойство (в данном случае Id) помечается как первичный ключ с автоинкрементом, EF Core оставляет его равным 0 в вашем DbContext до вызова SaveChanges(), а затем EF Core заполняет свойство Idс любым значением, сгенерированным для него SQL Server.

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)Я собираюсь предположить, что поле Id уже заполнено на данный момент, вызывая вашу ошибку.

[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);
}
...