Ingresando claves manualmente con Entity Framework

asp.net c# entity-framework entity-framework-core sql

Pregunta

Estoy tratando de usar el código de Entity Framework primero para un proyecto de base de datos simple y me encuentro con un problema que simplemente no puedo entender.

Noté que EF estaba configurando la ID para mis tablas aumentando automáticamente en 1 cada vez, ignorando completamente el valor que ingresé manualmente para ese campo. Después de algunas búsquedas, entiendo que la forma correcta de deshabilitar este comportamiento es:

modelBuilder.Entity<Event>().Property(e => e.EventID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

Sin embargo, ahora estoy recibiendo este error y no tengo idea de por qué:

Excepción no controlada: System.Data.Entity.Infrastructure.DbUpdateException: Se produjo un error al actualizar las entradas. Vea la excepción interna para más detalles. ---

System.Data.UpdateException: se produjo un error al actualizar las entradas. Vea la excepción interna para más detalles. ---> System.Data.SqlClient.SqlException: No se puede insertar un valor explícito para la columna de identidad en la tabla 'Eventos' cuando IDENTITY_INSERT está desactivado.

Si es útil, aquí está la clase POCO en cuestión:

public class Event
{
    [Key, Required]
    public int EventID { get; set; }

    public string EventType { get; set; } //TODO: Event Type Table later on
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }

    public virtual ICollection<Match> Matches { get; set; }
    public virtual ICollection<EventParticipation> EventParticipation { get; set; }
}

Gracias por adelantado.

Respuesta aceptada

Por defecto, Entity Framework asume que una clave primaria entera se genera en la base de datos (equivalente a agregar el atributo HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity) o Property(e => e.EventID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); llamada Property(e => e.EventID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); en el Fluent API.

Si observa la migración que crea la tabla, debería ver esto:

   CreateTable(
                "dbo.Events",
                c => new
                    {
                        EventID = c.Int(nullable: false, identity: true),
                        //etc
                    })
                .PrimaryKey(t => t.EventID );

Luego cambió el modelo utilizando la API Fluent a DatabaseGenerated.None . EF pone esto en la migración:

AlterColumn("dbo.Events", "EventID", c => c.Int(nullable: false, identity: false))

Y el sql generado es este:

ALTER TABLE [dbo].[Events] ALTER COLUMN [EventID] [int] NOT NULL

Que en realidad no se pone en cuclillas. Eliminar la IDENTIDAD de una columna no es trivial. Debe soltar y volver a crear la tabla o crear una nueva columna, luego debe copiar los datos y reparar las claves externas. Así que no es sorprendente que EF no esté haciendo eso por ti.

Tienes que encontrar la mejor manera de hacerlo por ti mismo. Podría revertir sus migraciones a 0 y volver a armar el andamio desde cero ahora que ha especificado DatabaseGeneratedOption.None , o puede cambiar la migración manualmente para eliminar y volver a crear la tabla.

O podrías soltar y recrear la columna:

DropColumn("Customer", "CustomerId"); 
AddColumn("Customer", "CustomerId", c => c.Long(nullable: false, identity: false));

EDITAR O puede activar / desactivar la identidad con una operación de migración personalizada


Respuesta popular

Ya que prefiero los atributos, aquí la alternativa para completar:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }

Nota: Esto funciona también en EF Core.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué