Entity Framework - Nom de colonne non valide '* _ID "

100

J'ai réduit cela à un problème entre Code First et Database first EF, mais je ne sais pas comment le résoudre. J'essaierai d'être aussi clair que possible, mais honnêtement, je manque une partie de la compréhension ici moi-même. C'est Entity Framework 4.4

J'ai hérité d'un projet dans lequel Entity Framework était utilisé, mais de nombreux fichiers réels ont été supprimés sans véritable moyen de revenir en arrière. J'ai ré-ajouté EF (base de données d'abord) et répliqué une configuration T4 autour de laquelle le projet a été construit. Il a généré des versions de code de tous les modèles de base de données et un fichier de code DBContext.

Si ma chaîne de connexion ressemble à une chaîne de connexion .NET "normale", j'obtiens une erreur concernant une colonne non valide. Le nom "ProcessState_ID" n'existe pas. ProcessState_ID n'est pas du tout dans la base de code, il n'est pas dans le fichier EDMX ou quoi que ce soit. Cela semble être une conversion EF automatique dans la requête.

Lorsque je fais correspondre la chaîne de connexion au modèle Entity Framework, cela fonctionne correctement.

Maintenant, en essayant de faire correspondre le code précédent avec Entity Framework, j'aimerais garder la chaîne de connexion .NET "normale".

J'ai donc deux questions ici: 1. Quel est le bon moyen de passer d'une chaîne de connexion normale à une chaîne de connexion EF dans le code? 2. Y a-t-il un autre correctif ici que je ne vois pas pour arrêter l'erreur de nom de colonne non valide?

Clarence Klopfstein
la source
3
Cela se produit également si vous avez une propriété de navigation avec seulement un accesseur get:public virtual Person Person { get; }
Şafak Gür

Réponses:

90

Vérifiez si vous avez des ICollections.

Ce que j'ai compris, c'est que lorsque vous avez une ICollection qui fait référence à une table et qu'il n'y a pas de colonne qu'elle puisse comprendre, elle en crée une pour que vous essayiez de faire la connexion entre les tables. Cela se produit spécifiquement avec ICollection et m'a poussé à essayer de le comprendre.

dessiné
la source
43
Juste pour être clair sur cette réponse, car elle était la plus précise pour ma situation (mais je ne l'ai su qu'après avoir résolu mon problème). Si vous rencontrez une erreur liée à OtherTable_ID lorsque vous récupérez Table, accédez à votre modèle OtherTable et assurez-vous que vous ne disposez pas d'ICollection <Table>. Sans une relation définie, le framework supposera automatiquement que vous devez avoir un FK vers OtherTable et créera ces propriétés supplémentaires dans le SQL généré.
LUKE
15
EF a gaspillé mes 4 heures
Nitin Sawant
2
@NitinSawant C'est tout? EF me gaspille 4 heures par jour avec toutes ses duplications et ses enregistrements non attachés.
Jacob
@LUKE Votre commentaire m'a sauvé. Je t'aime tellement :)
Amir Hossein Ahmadi
1
@LUKE le héros EF dont nous avons besoin, pas le héros EF que nous méritons. Je t'aime.
Matthew Young
63

C'est une entrée tardive pour ceux (comme moi) qui n'ont pas immédiatement compris les 2 autres réponses.

Alors...

EF essaie de mapper au nom ATTENDU à partir de la référence de clé de table de parents ... et puisque ... le nom de clé étrangère a été "modifié ou raccourci" dans la relation TABLEAU D'ENFANT de bases de données ... vous obtiendrez le message ci-dessus.

(ce correctif peut différer entre les versions d'EF)

POUR MOI, LE CORRECTIF ÉTAIT:
AJOUTER l'attribut "ForeignKey" au modèle

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; }
}
Prisonnier ZERO
la source
4
Cela a fonctionné pour moi. +1 pour être le seul endroit où j'ai trouvé cette réponse.
Jerry Benson-Montgomery
@Jerry J'ai défini la clé forign. Mais il recherche toujours le fichier Category_Id. Vous avez mentionné les correctifs pour différentes versions d'EF, n'est-ce pas? J'utilise EF 6.0. Quel est le correctif i canadopt?
Ajay Aradhya
@ ajay-aradhya En fait, c'est la personne qui a répondu à l'origine, prisonnier zéro, qui a fait le commentaire sur les différentes versions d'EF.
Jerry Benson-Montgomery
@ JerryBenson-Montgomery tant pis! je l'ai fait fonctionner. C'était le mappage «un à un» qui le poussait à rechercher *_ID. Y compris la référence arrière a bien fonctionné.
Ajay Aradhya
1
Vous pouvez également résoudre ce problème en ajoutant une classe partielle de métadonnées afin de ne pas avoir à résoudre ce problème lors de la régénération. [MetadataType(typeof(MetaData))] public partial class Tour { public class MetaData { [ForeignKey(nameof(TourCategory))] public virtual TourCategory TourCategory { get; set; } } }
Carter Medlin
39

Vache sacrée - après de nombreuses heures d'essais, j'ai finalement compris cela.

Je fais d'abord la base de données EF6 et je m'interrogeais sur l'erreur «colonne inconnue d'étendue» - elle générait le nom de la colonne de soulignement du nom de la table pour une raison quelconque, et essayait de trouver une colonne inexistante.

Dans mon cas, l'une de mes tables avait deux références de clé étrangère à la même clé primaire dans une autre table - quelque chose comme ceci:

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

EF générait un nom de colonne bizarre comme Owners_AnimalID1et Owners_AnimalID2puis a procédé à se briser.

L'astuce ici est que ces clés étrangères déroutantes doivent être enregistrées avec EF à l'aide de l'API Fluent!

Dans le contexte de votre base de données principale, remplacez la OnModelCreatingméthode et modifiez la configuration de l'entité. De préférence, vous aurez un fichier séparé qui étend la EntityConfigurationclasse, mais vous pouvez le faire en ligne.

Quoi qu'il en soit, vous devrez ajouter quelque chose comme ceci:

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

Et avec cela, EF commencera (peut-être) à fonctionner comme prévu. Boom.

En outre, vous obtiendrez la même erreur si vous utilisez ce qui précède avec une colonne Nullable - utilisez simplement à la .HasOptional()place de .HasRequired().


Voici le lien qui m'a mis sur la bosse:

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

Et puis, la documentation de l'API Fluent aide, en particulier les exemples de clés étrangères:

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

Vous pouvez également mettre les configurations à l'autre extrémité de la clé, comme décrit ici:

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

Il y a de nouveaux problèmes que je rencontre maintenant, mais c'était l'énorme lacune conceptuelle qui manquait. J'espère que ça aide!

Ben
la source
1
Merci beaucoup .. J'ai eu le même problème.
Sachin Parashar
14

Hypothèses:

  • Table
  • OtherTable
  • OtherTable_ID

Choisissez maintenant l'une des méthodes suivantes:


UNE)

Retirer ICollection<Table>

Si vous rencontrez une erreur liée au OtherTable_IDmoment de la récupération Table, accédez à votre OtherTablemodèle et assurez-vous que vous n'en avez pas ICollection<Table>. Sans une relation définie, le framework supposera automatiquement que vous devez avoir un FK vers OtherTable et créera ces propriétés supplémentaires dans le SQL généré.

Tout le crédit de cette réponse appartient à @LUKE. La réponse ci-dessus est son commentaire sous @drewid answer. Je pense que son commentaire est si clair que je l'ai réécrit comme réponse.


B)

  • Ajouter OtherTableIdàTable

et

  • Définir OtherTableIddans la Tablebase de données
RAM
la source
1
Une réponse si brillante!
Amir Hossein Ahmadi
Cette réponse a en effet sauvé de jour rapidement. et grâce à LUKE, j'ai lu son commentaire. Bien que @drewid ait réussi le dernier de la chaîne de réponses, c'était superbe et ce qui était nécessaire pour la plupart des personnes confrontées à cette situation.
Div Tiwari le
3

Dans mon cas, je définissais incorrectement une clé primaire composée de deux clés étrangères comme celle-ci:

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

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

L'erreur que j'obtenais était "nom de colonne non valide Bar_ID".

Spécifier correctement la clé primaire composite a résolu le problème:

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

...
Seth
la source
3

Pour moi, la cause de ce comportement était due à un problème de mappage défini avec l'API Fluent. J'avais 2 types liés, où le type A avait un objet de type B facultatif et le type B avait de nombreux objets A.

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

J'avais défini la cartographie avec une api fluide comme ceci:

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

Mais le problème était que ce type B avait une propriété de navigation List<A>, donc j'ai euSQLException Invalid column name A_Id

J'ai attaché le débogage de Visual Studio à EF DatabaseContext.Database.Log pour générer le SQL généré vers la sortie VS-> fenêtre de débogage

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

Et le SQL généré avait 2 relations de la table B -> une avec l'ID correct et l'autre avec le A_Id

Le problème pour le problème était que je n'ai pas ajouté cette B.List<A>propriété de navigation dans le mappage.

Voici donc comment, dans mon cas, une cartographie correcte devait être:

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

Dans mon cas, la cause de ce problème était une contrainte FOREIGN KEY manquante sur une base de données migrée. Ainsi, l'ICollection virtuelle existante n'a pas été chargée avec succès.

Stefan Michev
la source
1

J'ai également eu ce problème et il semble qu'il y ait plusieurs causes différentes. Pour moi, il s'agissait d'une propriété id définie par erreur comme int au lieu de long dans la classe parente qui contenait un objet de navigation. Le champ id dans la base de données a été défini comme bigint qui correspond à long en C #. Cela n'a pas causé d'erreur de compilation, mais a provoqué la même erreur d'exécution que l'OP obtenu:

// 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;
    }
}
Ciaran Bruen
la source
1

Pour moi, le problème est que j'ai fait mapper la table dans mon application deux fois - une fois via Code First, une fois via Database First.

Supprimer l'un ou l'autre résout le problème dans mon cas.

Renan
la source
1

Pour moi, c'est arrivé à cause des problèmes de pluralisation d'EF. Pour les tables qui se terminent par quelque chose comme "-Status", EF pense que le singulier est "-Statu". Le changement de l'entité et du nom de la table de base de données en "-StatusTypes" l'a corrigé.

De cette façon, vous n'aurez pas besoin de renommer les modèles d'entité à chaque fois qu'ils sont mis à jour.

Ray Lionfang
la source
0

Si vous avez plusieurs fois des références de clé étrangère à la même table, vous pouvez utiliser InverseProperty

Quelque chose comme ça-

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

Pour moi (en utilisant Visual Studio 2017 et le modèle basé sur la base de données sous Entity Framework 6.1.3), le problème a disparu après le redémarrage de Visual Studio et la reconstruction.

neuronz
la source
Cela ne semble pas une réponse définitive à la question puisque vous n'expliquez pas la cause. Cela devrait être mis en commentaire.
Ibo du
0

Dans mon cas, les données de ma méthode de semences appelaient toujours une colonne de table qui avait été supprimée lors d'une migration précédente. Vérifiez vos mappages si vous utilisez Automapper.

SauerTruite
la source
0

Dans mon cas, j'ai déjà une base de données (Database firts). Grâce à tous les commentaires ici, j'ai trouvé ma solution:

Les tables doivent avoir la relation mais le nom des colonnes doit être différent et ajouter l'attribut ForeignKey.

[ForeignKey ("PrestadorId")] public virtuel AwmPrestadoresServicios Colaboradores {get; ensemble; }

Autrement dit, PRE_ID est PK, mais FK dans l'autre table est PRESTADOR_ID, alors cela fonctionne. Merci à tous les commentaires ici j'ai trouvé ma solution. EF fonctionne de manière mystérieuse.

Mauricio Molina
la source
0

Si vous rencontrez ce problème avec une propriété de navigation sur la même table, vous devrez changer le nom de notre propriété.

Par exemple :

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

Vous devrez changer AncestorIdpour PersonId.

Il semble qu'EF tente de créer une clé ParentIdcar il n'a pas pu trouver une table nommée Ancestor ...

EDIT: C'est un correctif pour la base de données d'abord!

Pierre
la source