Entity Framework - Nome colonna non valido "* _ID"


100

Ho ristretto questo a qualche problema tra Code First e Database first EF, ma non sono sicuro di come risolverlo. Cercherò di essere il più chiaro possibile, ma onestamente mi manca un po 'di comprensione qui. Questo è Entity Framework 4.4

Ho ereditato un progetto in cui è stato utilizzato Entity Framework, ma molti dei file effettivi sono stati eliminati senza un vero modo per tornare indietro. Ho aggiunto di nuovo EF (Database first) e ho replicato una configurazione T4 su cui era stato costruito il progetto. Ha generato versioni di codice di tutti i modelli di database e un file di codice DBContext.

Se la mia stringa di connessione appare come una stringa di connessione .NET "normale", ricevo un errore su una colonna non valida. Il nome "ProcessState_ID" non esiste. ProcessState_ID non è affatto nel codice di base, non è nel file EDMX o altro. Questa sembra essere una conversione EF automatica nella query.

Quando faccio corrispondere la stringa di connessione al modello Entity Framework, funziona bene.

Ora, cercando di far corrispondere il codice precedente con Entity Framework, vorrei mantenere la stringa di connessione .NET "normale".

Quindi ho due domande qui: 1. Qual è un buon modo per passare da una normale stringa di connessione a una stringa di connessione EF nel codice? 2. C'è un'altra correzione qui che non vedo per fermare l'errore di nome di colonna non valido?


3
Ciò accade anche se si dispone di una proprietà di navigazione con solo una funzione di accesso get:public virtual Person Person { get; }
Şafak Gür

Risposte:


90

Controlla per vedere se hai ICollection.

Quello che ho capito è che quando hai una ICollection che fa riferimento a una tabella e non ci sono colonne che possa capire, ne crea una per te per provare a fare la connessione tra le tabelle. Questo accade in particolare con ICollection e mi ha reso "impazzito" cercando di capirlo.


43
Giusto per essere chiari su questa risposta, perché era più accurata per la mia situazione (ma non lo sapevo fino a dopo aver capito il mio problema). Se hai qualche errore relativo a OtherTable_ID quando stai recuperando Table, vai al tuo modello OtherTable e assicurati di non avere un ICollection <Table> lì. Senza una relazione definita, il framework presumerà automaticamente che sia necessario disporre di un FK per OtherTable e creerà queste proprietà extra nell'SQL generato.
LUKE

15
EF ha sprecato le mie 4 ore
Nitin Sawant

2
@ NitinSawant Questo è tutto? EF mi spreca 4 ore al giorno con tutte le sue duplicazioni e record non allegati.
Jacob,

@LUKE Il tuo commento mi ha salvato. Ti amo così tanto :)
Amir Hossein Ahmadi

1
@LUKE l'eroe EF di cui abbiamo bisogno, non l'eroe EF che ci meritiamo. Ti amo.
Matthew Young

63

Questa è una voce in ritardo per quelli (come me) che non hanno capito immediatamente le altre 2 risposte.

Così...

EF sta tentando di mappare al nome ATTESO dal RIFERIMENTO CHIAVE DELLE TABELLE GENITORI ... e poiché ... il nome CHIAVE ESTERA è stato "modificato o abbreviato" nei database relazione TABELLA BAMBINI ... riceverai il messaggio sopra.

(questa correzione può differire tra le versioni di EF)

PER ME LA CORREZIONE ERA:
AGGIUNGERE l'attributo "ForeignKey" al modello

public partial class Tour
{
    public Guid Id { get; set; }

    public Guid CategoryId { get; set; }

    [Required]
    [StringLength(200)]
    public string Name { get; set; }

    [StringLength(500)]
    public string Description { get; set; }

    [StringLength(50)]
    public string ShortName { get; set; }

    [StringLength(500)]
    public string TourUrl { get; set; }

    [StringLength(500)]
    public string ThumbnailUrl { get; set; }

    public bool IsActive { get; set; }

    [Required]
    [StringLength(720)]
    public string UpdatedBy { get; set; }

    [ForeignKey("CategoryId")]
    public virtual TourCategory TourCategory { get; set; }
}

4
Questo ha funzionato per me. +1 per essere l'unico posto in cui ho trovato questa risposta.
Jerry Benson-Montgomery

@ Jerry ho definito la chiave forign. Ma cerca ancora il file Category_Id. Hai menzionato le correzioni per diverse versioni di EF, giusto? sto usando EF 6.0 Qual è la correzione che posso adottare?
Ajay Aradhya

@ ajay-aradhya In realtà, è stata la persona che ha risposto originariamente, prisoner-zero, a fare il commento sulle diverse versioni di EF.
Jerry Benson-Montgomery

@ JerryBenson-Montgomery non importa! l'ho fatto funzionare. Era la mappatura "uno a uno" che lo faceva cercare *_ID. Compreso il riferimento posteriore ha funzionato bene.
Ajay Aradhya

1
Puoi anche risolvere questo problema aggiungendo una classe parziale di metadati in modo da non doverlo riparare quando rigeneri. [MetadataType(typeof(MetaData))] public partial class Tour { public class MetaData { [ForeignKey(nameof(TourCategory))] public virtual TourCategory TourCategory { get; set; } } }
Carter Medlin il

39

Vacca sacra - dopo molte ore di tentativi, finalmente l'ho capito.

Sto facendo prima il database EF6 e mi chiedevo l'errore "colonna sconosciuta di estensione": per qualche motivo stava generando il nome della colonna di sottolineatura del nome della tabella e cercavo di trovare una colonna inesistente.

Nel mio caso, una delle mie tabelle aveva due riferimenti a chiave esterna alla stessa chiave primaria in un'altra tabella, qualcosa del genere:

Animals            Owners
=======            ======
AnimalID (PK)      Pet1ID    <- FK to AnimalID
                   Pet2ID    <- also FK to AnimalID

EF stava generando qualche nome di colonna strano come Owners_AnimalID1e Owners_AnimalID2e poi proceduto a rompersi.

Il trucco qui è che queste chiavi esterne confuse devono essere registrate con EF utilizzando Fluent API!

Nel contesto del database principale, sovrascrivi il OnModelCreatingmetodo e modifica la configurazione dell'entità. Preferibilmente, avrai un file separato che estende la EntityConfigurationclasse, ma puoi farlo in linea.

In ogni caso, dovrai aggiungere qualcosa del genere:

public class OwnerConfiguration : EntityTypeConfiguration<Owner>
{
    public OwnerConfiguration()
    {
        HasRequired(x => x.Animals)
            .WithMany(x => x.Owners)  // Or, just .WithMany()
            .HasForeignKey(x => x.Pet1ID);
    }
}

E con questo, EF inizierà (forse) a funzionare come ti aspetti. Boom.

Inoltre, riceverai lo stesso errore se usi quanto sopra con una colonna nullable, basta usare .HasOptional()invece di .HasRequired().


Ecco il link che mi ha messo oltre la gobba:

https://social.msdn.microsoft.com/Forums/en-US/862abdae-b63f-45f5-8a6c-0bdd6eeabfdb/getting-sqlexception-invalid-column-name-userid-from-ef4-codeonly?forum=adonetefx

E poi, i documenti dell'API Fluent aiutano, in particolare gli esempi di chiavi esterne:

http://msdn.microsoft.com/en-us/data/jj591620.aspx

Puoi anche mettere le configurazioni all'altra estremità della chiave, come descritto qui:

http://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx .

Ci sono alcuni nuovi problemi che sto incontrando ora, ma quello era l'enorme divario concettuale che mancava. Spero che sia d'aiuto!


1
Grazie mille .. Ho avuto lo stesso problema.
Sachin Parashar

14

Presupposti:

  • Table
  • OtherTable
  • OtherTable_ID

Ora scegli uno di questi modi:


UN)

Rimuovere ICollection<Table>

Se hai qualche errore relativo a OtherTable_IDquando stai recuperando Table, vai al tuo OtherTablemodello e assicurati di non averne uno ICollection<Table>. Senza una relazione definita, il framework presumerà automaticamente che sia necessario disporre di un FK per OtherTable e creerà queste proprietà extra nell'SQL generato.

Tutto il merito di questa risposta appartiene a @LUKE. La risposta sopra è il suo commento sotto la risposta @drewid. Penso che il suo commento sia così pulito che l'ho riscritto come risposta.


B)

  • Aggiungi OtherTableIdaTable

e

  • Definire OtherTableIdnel Tabledatabase in

1
Una risposta così brillante!
Amir Hossein Ahmadi

Questa risposta in effetti salvò velocemente di giorno. e grazie a LUKE, ho letto il suo commento. Anche se @drewid è arrivato all'ultimo della catena di risposte, ma è stato fantastico e ciò che era necessario per la maggior parte di fronte a questa situazione.
Div Tiwari

3

Nel mio caso stavo definendo in modo errato una chiave primaria composta da due chiavi esterne come questa:

HasKey(x => x.FooId);
HasKey(x => x.BarId);

HasRequired(x => x.Foo)
    .WithMany(y => y.Foos);
HasRequired(x => x.Bar);

L'errore che stavo ricevendo era "nome colonna non valido Bar_ID".

La specifica della chiave primaria composita ha risolto correttamente il problema:

HasKey(x => new { x.FooId, x.BarId });

...

3

Per me la causa di questo comportamento era dovuta a un problema con la mappatura definita con Fluent API. Avevo 2 tipi correlati, in cui il tipo A aveva un oggetto di tipo B opzionale e il tipo B aveva molti oggetti A.

public class A 
{
    
    public int? BId {get; set;}
    public B NavigationToBProperty {get; set;}
}
public class B
{
    
    public List<A> ListOfAProperty {get; set;}
}

Avevo definito la mappatura con api fluente come questa:

A.HasOptional(p=> p.NavigationToBProperty).WithMany().HasForeignKey(key => key.BId);

Ma il problema era che quel tipo B aveva la proprietà di navigazione List<A>, quindi di conseguenza avevoSQLException Invalid column name A_Id

Ho collegato Visual Studio Debug a EF DatabaseContext.Database.Log all'output dell'SQL generato in VS Output-> Debug window

db.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);

E l'SQL generato aveva 2 relazioni dalla tabella B -> una con ID corretto e l'altra con A_Id

Il problema per il problema era che non ho aggiunto questa B.List<A>proprietà di navigazione nella mappatura.

Quindi questo è come nel mio caso doveva essere la mappatura corretta:

A.HasOptional(p=> p.NavigationToBProperty).WithMany(x => x.ListOfAProperty).HasForeignKey(key => key.BId);

2

Nel mio caso la causa di questo problema era un vincolo FOREIGN KEY mancante su un database migrato. Quindi l'ICollection virtuale esistente non è stato caricato correttamente.


1

Ho anche avuto questo problema e sembra che ci siano alcune cause diverse. Per me era avere una proprietà id erroneamente definita come int invece che long nella classe genitore che conteneva un oggetto di navigazione. Il campo id nel database è stato definito come bigint che corrisponde a long in C #. Ciò non ha causato un errore in fase di compilazione ma ha causato lo stesso errore di run-time ottenuto dall'OP:

// Domain model parent object
public class WidgetConfig 
{
    public WidgetConfig(long id, int stateId, long? widgetId)
    {
        Id = id;
        StateId = stateId;
        WidgetId = widgetId;
    }

    private WidgetConfig()
    {
    }

    public long Id { get; set; }

    public int StateId { get; set; }

    // Ensure this type is correct
    public long? WidgetId { get; set; } 

    public virtual Widget Widget { get; set; }
}

// Domain model object
public class Widget
{
    public Widget(long id, string name, string description)
    {
        Id = id;
        Name = name;
        Description = description;
    }

    private Widget()
    {
    }

    public long Id { get; set; }

    public string Name { get; set; }

    public string Description { get; set; }
}

// EF mapping
public class WidgetConfigMap : EntityTypeConfiguration<WidgetConfig>
{
    public WidgetConfigMap()
    {
        HasKey(x => x.Id);
        ToTable(nameof(WidgetConfig));
        Property(x => x.Id).HasColumnName(nameof(WidgetConfig.Id)).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).IsRequired();
        Property(x => x.StateId).HasColumnName(nameof(WidgetConfig.StateId));
        Property(x => x.WidgetId).HasColumnName(nameof(WidgetConfig.WidgetId));
    }
}   

// Service
public class WidgetsService : ServiceBase, IWidgetsService
{
    private IWidgetsRepository _repository;

    public WidgetsService(IWidgetsRepository repository)
    {
        _repository = repository;
    }

    public List<WidgetConfig> ListWithDetails()
    {
        var list = _repository.ListWithDetails();

        return new WidgetConfigMapping().ConvertModelListToDtoList(list).ToList();
    }
}   

// Repository
public class WidgetsRepository: BaseRepository<WidgetConfig, long>, IWidgetsRepository
{
    public WidgetsRepository(Context context)
        : base(context, id => widget => widget.Id == id)
    {
    }

    public IEnumerable<WidgetConfig> ListWithDetails()
    {
        var widgets = Query
            .Include(x => x.State)
            .Include(x => x.Widget);

        return widgets;
    }
}

1

Per me il problema è che ho mappato la tabella nella mia app due volte: una volta tramite Code First, una volta tramite Database First.

La rimozione di uno dei due risolve il problema nel mio caso.


1

Per me, è successo a causa dei problemi di pluralizzazione di EF. Per le tabelle che terminano con qualcosa come "-Status", EF pensa che sia singolare "-Statu". La modifica dell'entità e del nome della tabella DB in "-StatusTypes" ha risolto il problema.

In questo modo, non sarà necessario rinominare i modelli di entità ogni volta che vengono aggiornati.


0

Se hai più di una volta riferimenti a chiavi esterne alla stessa tabella, puoi usare InverseProperty

Qualcosa come questo-

[InverseProperty("MyID1")]
public virtual ICollection<MyTable> set1 { get; set; }
[InverseProperty("MyID2")]
public virtual ICollection<MyTable> set2 { get; set; }

0

Per me (utilizzando Visual Studio 2017 e il modello database-first in Entity Framework 6.1.3), il problema è scomparso dopo il riavvio di Visual Studio e la ricostruzione.


Questa non sembra una risposta definitiva alla domanda poiché non spieghi la causa. Dovrebbe essere messo come commento.
Ibo

0

Nel mio caso i dati del mio metodo seed stavano ancora chiamando una colonna della tabella che era stata eliminata in una migrazione precedente. Controlla le tue mappature se stai usando Automapper.


0

Nel mio caso, ho già un database (Database firts). Grazie a tutti i commenti qui, ho trovato la mia soluzione:

Le tabelle devono avere la relazione ma il nome delle colonne deve essere diverso e aggiungere l'attributo ForeignKey.

[ForeignKey ("PrestadorId")] AwmPrestadoresServicios Colaboradores virtuali pubblici {get; impostato; }

Cioè, PRE_ID è PK, ma FK nell'altra tabella è PRESTADOR_ID, quindi funziona. Grazie a tutti i commenti qui ho trovato la mia soluzione. EF funziona in modi misteriosi.


0

Se hai questo problema con una proprietà di navigazione sulla stessa tabella, dovrai cambiare il nome della nostra proprietà.

Per esempio :

Table : PERSON
Id
AncestorId (with a foreign key which references Id named Parent) 

Dovrai cambiare AncestorIdper PersonId.

Sembra che EF stia cercando di creare una chiave ParentIdperché non è riuscito a trovare una tabella denominata Ancestor ...

EDIT: questa è prima una correzione per il database!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.