C# Cannot insert explicit value for identity colum

2020-05-04 07:33发布

问题:

I am currently learning ASP.NET MVC and I'm learning to get an object via its ID and inserting its reference to the database. However, I am getting this error

Cannot insert explicit value for identity column in table "Rentals" when IDENTITY_INSERT is set to OFF

I have read around and I noticed that some people say to set identity insert to off because the ID of the referenced table is auto incremented? However I have read that this method is not recommended because it apparently locks off the table or is only useful for single users? May I know what is the correct way to do this?

This is my controller code that is trying to add a new Rental

[HttpPost]
public IHttpActionResult CreateNewRental(RentalDTO RentalDTO)
{
    if (RentalDTO.MovieIds.Count == 0)
    {
        return BadRequest();
    }
    var customer = _context.Customers.SingleOrDefault(c => c.Id == RentalDTO.CustomerId);
    if (customer == null)
    {
        return BadRequest("Customer ID is not valid");
    }
    var movies = _context.Movies.Where(m => RentalDTO.MovieIds.Contains(m.Id)).ToList();
    if (movies.Count != RentalDTO.MovieIds.Count)
    {
        return BadRequest();
    }
    foreach (var movie in movies)
    {
        if (movie.NumberAvailable < 1)
        {
             return BadRequest();
        }
        movie.NumberAvailable--;
        var rental = new Rentals
        {
            Customer = customer,
            Movie = movie,
            DateRented = DateTime.Now,
        };
        _context.Rentals.Add(rental);
    }
    _context.SaveChanges();
    return Ok();
}

This is my rentals model

public class Rentals
{
    public byte Id { get; set; }
    [Required]
    public Customers Customer { get; set; }
    [Required]
    public Movies Movie { get; set; }
    public DateTime DateRented { get; set; }
    public DateTime? DateReturned { get; set; }
}

This is the migration I used to create the table

CreateTable(
            "dbo.Rentals",
            c => new
                {
                    Id = c.Byte(nullable: false, identity: true),
                    DateRented = c.DateTime(nullable: false),
                    DateReturned = c.DateTime(),
                    Customer_Id = c.Int(nullable: false),
                    Movie_Id = c.Int(nullable: false),
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.Customers", t => t.Customer_Id, cascadeDelete: true)
            .ForeignKey("dbo.Movies", t => t.Movie_Id, cascadeDelete: true)
            .Index(t => t.Customer_Id)
            .Index(t => t.Movie_Id);

UPDATE:

I have debugged my code and realized that when I added a new Rental, 0 was set as the ID. How do I set that automatically?

回答1:

One of the columns in your Rentals table is an identity column (guessing it's the ID column). You generally don't want to explicitly set the value of an identity column, so your SQL server doesn't allow you without turning an option (IDENTITY_INSERT) on.

To avoid this problem, whatever mechanism you are using to save changes needs to know that when inserting, you don't specify the identity column. Instead, you specify the rest of the columns and let the database decide the value of the identity column. Similarly when updating, you won't generally be modifying this column, so your update shouldn't attempt to change it.

If you provide more information about what framework you're using for your model saving, we may be able to provide more specific answers.

This all changes if you actually have a need to specify a particular value for an identity column (such as copying data from one database to another is one example I've personally done this). In that case, you can use the statement set IDENTITY_INSERT ON to allow the insert, then turn it back off when you're done.



回答2:

We ran into this issue today, also on a byte-type identity column. It didn't happen on the tables with an int-type identity column, but in the case of the byte column, what we assumed to be default behaviour was not being followed. Despite it being marked with HasKey under the entity configuration, our system was still attempting to insert a value into the identity column.

The solution that we found was the addition of a Property within the entity's configuration, marking it explicitly as having its value generated by the database:

Property(c => c.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

(with using System.ComponentModel.DataAnnotations.Schema)

Once we set this property, the identity-insert bug was resolved.