Entity Framework: nombre de columna no válido '* _ID "

100

He reducido esto a un problema entre Code First y Database first EF, pero no estoy seguro de cómo solucionarlo. Trataré de ser lo más claro posible, pero, sinceramente, me estoy perdiendo parte de la comprensión aquí. Esto es Entity Framework 4.4

Heredé un proyecto en el que se utilizó Entity Framework, pero muchos de los archivos reales se eliminaron sin una forma real de volver atrás. Volví a agregar EF (la base de datos primero) y repliqué una configuración T4 sobre la que se construyó el proyecto. Generaba versiones de código de todos los modelos de base de datos y un archivo de código DBContext.

Si mi cadena de conexión parece una cadena de conexión .NET "normal", obtengo un error sobre una columna no válida. El nombre "ProcessState_ID" no existe. ProcessState_ID no está en la base del código en absoluto, no está en el archivo EDMX ni nada. Esto parece ser una conversión EF automática en la consulta.

Cuando hago que la cadena de conexión coincida con el modelo de Entity Framework, funciona bien.

Ahora, al intentar hacer coincidir el código anterior con Entity Framework, me gustaría mantener la cadena de conexión .NET "normal".

Entonces tengo dos preguntas aquí: 1. ¿Cuál es una buena manera de pasar de una cadena de conexión normal a una cadena de conexión EF en el código? 2. ¿Hay otra solución aquí que no veo para detener el error de nombre de columna no válido?

Clarence Klopfstein
fuente
3
Esto también sucede si tiene una propiedad de navegación con solo un descriptor de acceso get:public virtual Person Person { get; }
Şafak Gür

Respuestas:

90

Compruebe si tiene ICollections.

Lo que he descubierto es que cuando tienes un ICollection que hace referencia a una tabla y no hay una columna que pueda descifrar, crea una para que intentes hacer la conexión entre las tablas. Esto sucede específicamente con ICollection y me ha vuelto "loco" tratando de resolverlo.

drewid
fuente
43
Solo para ser claro en esta respuesta, porque era más precisa para mi situación (pero no lo supe hasta que descubrí mi problema). Si tiene algún error relacionado con OtherTable_ID cuando está recuperando la Tabla, vaya a su modelo de OtherTable y asegúrese de que no tiene una ICollection <Table> allí. Sin una relación definida, el marco asumirá automáticamente que debe tener un FK para OtherTable y creará estas propiedades adicionales en el SQL generado.
LUKE
15
EF desperdició mis 4 horas
Nitin Sawant
2
@NitinSawant ¿Eso es todo? EF me desperdicia 4 horas al día con todas sus duplicaciones y registros no adjuntos.
Jacob
@LUKE Tu comentario me salvó. Te quiero mucho :)
Amir Hossein Ahmadi
1
@LUKE el héroe EF que necesitamos, no el héroe EF que merecemos. te quiero.
Matthew Young
62

Esta es una entrada tardía para aquellos (como yo) que no entendieron de inmediato las otras 2 respuestas.

Entonces...

EF está tratando de mapear el nombre ESPERADO de la REFERENCIA DE CLAVE DE LAS TABLAS DE LOS PADRES ... y dado que ... el nombre de la CLAVE EXTRANJERA fue "cambiado o acortado" en la relación de la TABLA DE NIÑOS de las bases de datos ... obtendría el mensaje de arriba.

(esta solución puede diferir entre las versiones de EF)

PARA MÍ, LA SOLUCIÓN FUE:
AGREGAR el atributo "ForeignKey" al modelo

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; }
}
Prisionero CERO
fuente
4
Esto funcionó para mí. +1 por ser el único lugar donde encontré esta respuesta.
Jerry Benson-Montgomery
@ Jerry Tengo la clave forign definida. Pero aún busca el Category_Id. Ha mencionado acerca de las correcciones para diferentes versiones de EF, ¿verdad? Estoy usando EF 6.0 ¿Cuál es la solución que puedo solucionar?
Ajay Aradhya
@ ajay-aradhya En realidad, fue la persona que respondió originalmente, prisoner-zero, quien hizo el comentario sobre las diferentes versiones de EF.
Jerry Benson-Montgomery
@ JerryBenson-Montgomery ¡no importa! Lo hice funcionar. Era el mapeo 'uno a uno' lo que hacía que buscara *_ID. Incluir la referencia posterior funcionó bien.
Ajay Aradhya
1
También puede solucionar esto agregando una clase parcial de metadatos para que no tenga que arreglar esto cuando vuelva a generar. [MetadataType(typeof(MetaData))] public partial class Tour { public class MetaData { [ForeignKey(nameof(TourCategory))] public virtual TourCategory TourCategory { get; set; } } }
Carter Medlin
39

Santo cielo, después de muchas horas de intentarlo, finalmente me di cuenta de esto.

Primero estoy haciendo la base de datos EF6 y me preguntaba sobre el error de "columna desconocida de extensión": estaba generando el nombre de la tabla con el nombre de la columna de subrayado por alguna razón y tratando de encontrar una columna inexistente.

En mi caso, una de mis tablas tenía dos referencias de clave externa a la misma clave principal en otra tabla, algo como esto:

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

EF estaba generando algún nombre de la columna extraño como Owners_AnimalID1y Owners_AnimalID2y luego procedió a romperse.

¡El truco aquí es que estas confusas claves externas deben registrarse con EF usando Fluent API!

En el contexto de su base de datos principal, anule el OnModelCreatingmétodo y cambie la configuración de la entidad. Preferiblemente, tendrá un archivo separado que amplía la EntityConfigurationclase, pero puede hacerlo en línea.

De cualquier forma que lo haga, deberá agregar algo como esto:

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

Y con eso, EF (quizás) comenzará a funcionar como esperabas. Auge.

Además, obtendrá el mismo error si usa lo anterior con una columna anulable, solo use en .HasOptional()lugar de .HasRequired().


Aquí está el enlace que me puso sobre la joroba:

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

Y luego, los documentos de Fluent API ayudan, especialmente los ejemplos de clave externa:

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

También puede poner las configuraciones en el otro extremo de la llave, como se describe aquí:

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

Hay algunos problemas nuevos con los que me estoy enfrentando ahora, pero esa era la gran brecha conceptual que faltaba. ¡Espero eso ayude!

Ben
fuente
1
Muchas gracias .. Tuve el mismo problema.
Sachin Parashar
14

Supuestos:

  • Table
  • OtherTable
  • OtherTable_ID

Ahora elija una de estas formas:


UNA)

Eliminar ICollection<Table>

Si tiene algún error relacionado con el OtherTable_IDmomento en que está recuperando Table, vaya a su OtherTablemodelo y asegúrese de que no tenga un ICollection<Table>archivo allí. Sin una relación definida, el marco asumirá automáticamente que debe tener un FK para OtherTable y creará estas propiedades adicionales en el SQL generado.

Todo el crédito de esta respuesta pertenece a @LUKE. La respuesta anterior es su comentario en la respuesta de @drewid. Creo que su comentario es tan limpio que lo reescribí como respuesta.


SI)

  • Agregar OtherTableIdaTable

y

  • Definir OtherTableIden la Tablebase de datos
RAM
fuente
1
¡Qué respuesta tan brillante!
Amir Hossein Ahmadi
Esta respuesta de hecho se salvó rápidamente durante el día. y gracias a LUKE, leí su comentario. Aunque @drewid llegó al último de la cadena de respuestas, fue excelente y lo que se necesitaba para la mayoría de las personas que enfrentan esta situación.
Div Tiwari
3

En mi caso, estaba definiendo incorrectamente una clave principal compuesta por dos claves externas como esta:

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

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

El error que recibía era "nombre de columna no válido Bar_ID".

Especificar la clave primaria compuesta correctamente solucionó el problema:

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

...
Seth
fuente
3

Para mí, la causa de este comportamiento se debió a un problema con el mapeo definido con Fluent API. Tenía 2 tipos relacionados, donde el tipo A tenía un objeto de tipo B opcional y el tipo B tenía muchos objetos A.

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

Había definido el mapeo con una api fluida como esta:

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

Pero el problema era que el tipo B tenía propiedad de navegación List<A>, por lo que tuveSQLException Invalid column name A_Id

Adjunté Visual Studio Debug a EF DatabaseContext.Database.Log para generar SQL generado a VS Output-> Debug window

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

Y el SQL generado tenía 2 relaciones de la tabla B -> una con la identificación correcta y otra con la A_Id

El problema del problema era que no agregué esta B.List<A>propiedad de navegación al mapeo.

Así es como en mi caso tenía que ser el mapeo correcto:

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

En mi caso, la causa de este problema fue una restricción de LLAVE EXTRANJERA faltante en una base de datos migrada. Por lo tanto, la colección virtual virtual existente no se cargó correctamente.

Stefan Michev
fuente
1

También tuve este problema y parece que hay algunas causas diferentes. Para mí, tenía una propiedad id definida erróneamente como int en lugar de long en la clase principal que contenía un objeto de navegación. El campo id en la base de datos se definió como bigint que corresponde a long en C #. Esto no causó un error de tiempo de compilación, pero causó el mismo error de tiempo de ejecución que obtuvo el 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;
    }
}
Ciaran Bruen
fuente
1

Para mí, el problema es que tuve la tabla asignada en mi aplicación dos veces: una a través de Code First, una vez a través de Database First.

Eliminar cualquiera de los dos resuelve el problema en mi caso.

Renan
fuente
1

Para mí, sucedió debido a los problemas de pluralización de EF. Para las tablas que terminan con algo como "-Status", EF piensa que su singular es "-Statu". Cambiar la entidad y el nombre de la tabla de la base de datos a "-StatusTypes" lo solucionó.

De esta manera, no necesitaría cambiar el nombre de los modelos de entidad cada vez que se actualiza.

Ray Lionfang
fuente
0

Si tiene referencias de clave externa a la misma tabla más de una vez, puede usar InverseProperty

Algo como esto-

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

Para mí (usando Visual Studio 2017 y el modelo de base de datos primero en Entity Framework 6.1.3), el problema desapareció después de reiniciar Visual Studio y Rebuilding.

neuronz
fuente
Esta no parece una respuesta definitiva a la pregunta, ya que no explica la causa. Debe ponerse como comentario.
Ibo
0

En mi caso, los datos de mi método de inicialización seguían llamando a una columna de tabla que se había eliminado en una migración anterior. Verifique sus asignaciones si está utilizando Automapper.

SauerTrout
fuente
0

En mi caso, ya tengo una base de datos (Database first). Gracias a todos los comentarios aquí, encontré mi solución:

Las tablas deben tener la relación, pero el nombre de las columnas debe ser diferente y agregar el atributo ForeignKey.

[ForeignKey ("PrestadorId")] público virtual AwmPrestadoresServicios Colaboradores {get; conjunto; }

Es decir, PRE_ID es PK, pero FK en la otra tabla es PRESTADOR_ID, entonces funciona. Gracias a todos los comentarios aquí encontré mi solución. EF funciona de formas misteriosas.

Mauricio molina
fuente
0

Si tiene este problema con una propiedad de navegación en la misma tabla, tendrá que cambiar el nombre de nuestra propiedad.

Por ejemplo :

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

Vas a tener que cambiar AncestorIdde PersonId.

Parece que EF está tratando de crear una clave ParentIdporque no pudo encontrar una tabla llamada Ancestor ...

EDITAR: ¡Esta es una solución para la base de datos primero!

Pierre
fuente