Immissione manuale delle chiavi con Entity Framework

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

Domanda

Sto provando a utilizzare il codice Entity Framework per un semplice progetto di database e mi imbatto in un problema che non riesco a capire.

Ho notato che EF stava impostando l'ID dei miei tavoli automaticamente aumentando di 1 ogni volta, ignorando completamente il valore inserito manualmente per quel campo. Dopo alcune ricerche, ho capito che il modo giusto per disabilitare questo comportamento è:

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

Comunque ora sto ricevendo questo errore e non ho idea del perché:

Eccezione non gestita: System.Data.Entity.Infrastructure.DbUpdateException: si è verificato un errore durante l'aggiornamento delle voci. Vedi l'eccezione interna per i dettagli. ---

System.Data.UpdateException: si è verificato un errore durante l'aggiornamento delle voci. Vedi l'eccezione interna per i dettagli. ---> System.Data.SqlClient.SqlException: impossibile inserire il valore esplicito per la colonna Identity nella tabella "Events" quando IDENTITY_INSERT è impostato su OFF.

Se è utile, ecco la classe POCO in questione:

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; }
}

Grazie in anticipo.

Risposta accettata

Per impostazione predefinita, Entity Framework presuppone che una chiave primaria intera sia generata dal database (equivalente all'aggiunta di HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity) o alla chiamata Property(e => e.EventID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); in Fluent API.

Se osservi la migrazione che crea la tabella dovresti vedere questo:

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

Quindi è stato modificato il modello utilizzando l'API Fluent in DatabaseGenerated.None . EF lo inserisce nella migrazione:

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

E lo sql generato è questo:

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

Che in realtà fa accovacciarsi. Eliminare l'IDENTITÀ da una colonna non è banale. È necessario eliminare e ricreare la tabella o creare una nuova colonna, quindi è necessario copiare i dati e correggere le chiavi esterne. Quindi non sorprende che EF non stia facendo questo per te.

Devi capire il modo migliore per farlo da solo. È possibile ripristinare le migrazioni su 0 e re-impalcature da zero ora che è stato specificato DatabaseGeneratedOption.None oppure è possibile modificare manualmente la migrazione per eliminare e ricreare la tabella.

Oppure puoi rilasciare e ricreare la colonna:

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

MODIFICA O è possibile attivare / disattivare l'identità con un'operazione di migrazione personalizzata


Risposta popolare

Dal momento che preferisco gli attributi, qui l'alternativa per motivi di completezza:

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

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

Nota: questo funziona anche in EF Core.



Related

Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow