Entity Framework - Nome de coluna inválido '* _ID "

100

Eu reduzi isso a algum problema entre o Code First e o Database First EF, mas não tenho certeza de como corrigi-lo. Tentarei ser o mais claro possível, mas, honestamente, estou perdendo parte do entendimento aqui. Este é o Entity Framework 4.4

Eu herdei um projeto em que o Entity Framework foi usado, mas muitos dos arquivos reais foram excluídos sem nenhuma maneira real de voltar. Eu adicionei novamente EF (primeiro banco de dados) e repliquei uma configuração T4 em torno da qual o projeto foi construído. Ele gerou versões de código de todos os modelos de banco de dados e um arquivo de código DBContext.

Se minha string de conexão parecer uma string de conexão .NET "normal", recebo um erro sobre uma coluna inválida O nome "ProcessState_ID" não existe. ProcessState_ID não está na base de código, não está no arquivo EDMX nem nada. Esta parece ser uma conversão automática de EF na consulta.

Quando eu faço a string de conexão corresponder ao modelo do Entity Framework, ele funciona bem.

Agora, ao tentar combinar o código anterior com o Entity Framework, gostaria de manter a cadeia de conexão .NET "normal".

Portanto, tenho duas perguntas aqui: 1. Qual é uma boa maneira de ir de uma string de conexão normal para uma string de conexão EF no código? 2. Existe outra correção aqui que não estou vendo para interromper o erro de nome de coluna inválido?

Clarence Klopfstein
fonte
3
Isso também acontece se você tiver uma propriedade de navegação com apenas um acessador get:public virtual Person Person { get; }
Şafak Gür

Respostas:

90

Verifique se você tem alguma ICollection.

O que eu descobri é que quando você tem um ICollection que faz referência a uma tabela e não há uma coluna que ele possa descobrir, ele cria uma para você tentar fazer a conexão entre as tabelas. Isso acontece especificamente com ICollection e me deixou "maluco" tentando descobrir isso.

desenhou
fonte
43
Só para esclarecer essa resposta, porque era a mais precisa para a minha situação (mas eu não sabia até descobrir meu problema). Se você tiver algum erro relacionado a OtherTable_ID quando estiver recuperando a tabela, vá para o seu modelo OtherTable e certifique-se de não ter uma ICollection <Table> lá. Sem um relacionamento definido, a estrutura assumirá automaticamente que você deve ter um FK para OtherTable e criará essas propriedades extras no SQL gerado.
LUKE de
15
EF desperdiçou minhas 4 horas
Nitin Sawant
2
@NitinSawant É isso? EF me faz perder 4 horas por dia com todas as suas duplicações e registros não anexados.
Jacob
@LUKE Seu comentário me salvou. Eu te amo muito :)
Amir Hossein Ahmadi
1
@LUKE o herói EF que precisamos, não o herói EF que merecemos. Eu te amo.
Matthew Young
62

Esta é uma entrada tardia para aqueles (como eu) que não entenderam imediatamente as outras 2 respostas.

Assim...

EF está tentando mapear para o nome ESPERADO da REFERÊNCIA-CHAVE DAS TABELAS PAIS ... e como ... o nome da CHAVE ESTRANGEIRA foi "alterado ou encurtado" nos bancos de dados relacionamento CHILD TABLE ... você receberá a mensagem acima.

(esta correção pode ser diferente entre as versões do EF)

PARA MIM, A CORREÇÃO FOI:
ADICIONAR o atributo "ForeignKey" ao 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; }
}
Prisioneiro ZERO
fonte
4
Isso funcionou para mim. 1 por ser o único lugar que encontrei essa resposta.
Jerry Benson-Montgomery
@Jerry tenho a chave estrangeira definida. Mas ainda procura o Category_Id. Você mencionou sobre as correções para diferentes versões do EF, certo? estou usando EF 6.0. Qual é a correção i canadopt?
Ajay Aradhya
@ ajay-aradhya Na verdade, foi a pessoa que respondeu originalmente, prisioneiro-zero, que fez o comentário sobre as diferentes versões de EF.
Jerry Benson-Montgomery
@ JerryBenson-Montgomery, deixa pra lá! eu fiz funcionar. Era o mapeamento 'um para um' que o fazia pesquisar *_ID. Incluir a referência anterior funcionou bem.
Ajay Aradhya,
1
Você também pode corrigir isso adicionando uma classe parcial de metadados para que não precise corrigir isso ao gerar novamente. [MetadataType(typeof(MetaData))] public partial class Tour { public class MetaData { [ForeignKey(nameof(TourCategory))] public virtual TourCategory TourCategory { get; set; } } }
Carter Medlin
39

Caramba - depois de muitas horas tentando, eu finalmente descobri isso.

Estou fazendo o banco de dados EF6 primeiro e estava me perguntando sobre o erro de "coluna desconhecida de extensão" - ele estava gerando nome de tabela sublinhado nome de coluna por algum motivo e tentando encontrar uma coluna inexistente.

No meu caso, uma das minhas tabelas tinha duas referências de chave estrangeira para a mesma chave primária em outra tabela - algo assim:

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

EF foi gerando algum nome da coluna estranho como Owners_AnimalID1e Owners_AnimalID2e então passou a quebrar-se.

O truque aqui é que essas chaves estrangeiras confusas precisam ser registradas no EF usando a API Fluent!

No contexto do banco de dados principal, substitua o OnModelCreatingmétodo e altere a configuração da entidade. De preferência, você terá um arquivo separado que estende a EntityConfigurationclasse, mas você pode fazer isso embutido.

De qualquer maneira, você precisará adicionar algo como isto:

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

E com isso, a EF vai (talvez) começar a funcionar como você espera. Estrondo.

Além disso, você obterá o mesmo erro se usar o acima com uma coluna anulável - apenas use em .HasOptional()vez de .HasRequired().


Aqui está o link que me colocou sobre o abismo:

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 então, os documentos da API Fluent ajudam, especialmente os exemplos de chave estrangeira:

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

Você também pode colocar as configurações na outra extremidade da chave, conforme descrito aqui:

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

Há alguns novos problemas que estou enfrentando agora, mas essa era a grande lacuna conceitual que estava faltando. Espero que ajude!

Ben
fonte
1
Muito obrigado .. Eu tive o mesmo problema.
Sachin Parashar
14

Premissas:

  • Table
  • OtherTable
  • OtherTable_ID

Agora escolha uma das seguintes maneiras:


A)

Remover ICollection<Table>

Se você tiver algum erro relacionado a OtherTable_IDquando está recuperando Table, vá até o seu OtherTablemodelo e certifique-se de que não há um ICollection<Table>lá. Sem um relacionamento definido, a estrutura assumirá automaticamente que você deve ter um FK para OtherTable e criará essas propriedades extras no SQL gerado.

Todo o crédito desta resposta pertence a @LUKE. A resposta acima é seu comentário em @drewid response. Acho que o comentário dele é tão claro que o reescrevi como uma resposta.


B)

  • Adicionar OtherTableIdaTable

e

  • Definir OtherTableIdno Tablebanco de dados
RAM
fonte
1
Que resposta brilhante!
Amir Hossein Ahmadi
Esta resposta realmente economizou por dia rapidamente. e graças ao LUKE, li o comentário dele. Embora @drewid tenha conseguido chegar ao fim da cadeia de respostas, foi excelente e o que era necessário para a maioria das pessoas que enfrentam essa situação.
Div Tiwari
3

No meu caso, eu estava definindo incorretamente uma chave primária composta de duas chaves estrangeiras como esta:

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

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

O erro que estava recebendo era "nome de coluna inválido Bar_ID".

Especificar a chave primária composta corrigiu o problema corretamente:

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

...
Seth
fonte
3

Para mim, a causa desse comportamento foi devido ao problema com o mapeamento definido com API Fluent. Eu tinha 2 tipos relacionados, onde o tipo A tinha um objeto tipo B opcional e o tipo B tinha muitos objetos A.

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

Eu tinha definido o mapeamento com API fluente assim:

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

Mas o problema era que aquele tipo B tinha propriedade de navegação List<A>, então como resultado eu tiveSQLException Invalid column name A_Id

Anexei o Visual Studio Debug ao EF DatabaseContext.Database.Log para gerar o SQL gerado na Saída do VS-> janela de depuração

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

E o SQL gerado tinha 2 relações da tabela B -> uma com id correto e outra com o A_Id

A questão para o problema era que eu não adicionei essa B.List<A>propriedade de navegação ao mapeamento.

Portanto, no meu caso, é assim que o mapeamento correto deveria ser:

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

No meu caso, a causa desse problema foi uma restrição FOREIGN KEY ausente em um banco de dados migrado. Portanto, o ICollection virtual existente não foi carregado com êxito.

Stefan Michev
fonte
1

Eu também tive esse problema e parece que existem algumas causas diferentes. Para mim, era uma propriedade id definida por engano como int em vez de long na classe pai que continha um objeto de navegação. O campo id no banco de dados foi definido como bigint que corresponde a long em C #. Isso não causou um erro de tempo de compilação, mas causou o mesmo erro de tempo de execução que o OP obteve:

// 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
fonte
1

Para mim, o problema é que mapeei a tabela em meu aplicativo duas vezes - uma vez por meio do Code First e outra por meio do Database First.

Remover qualquer um resolve o problema no meu caso.

Renan
fonte
1

Para mim, isso aconteceu por causa dos problemas de pluralização da EF. Para tabelas que terminam com algo como "-Status", EF pensa que é singular é "-Statu". Alterar a entidade e o nome da tabela de banco de dados para "-StatusTypes" corrigiu o problema.

Dessa forma, você não precisaria renomear os modelos de entidade sempre que eles fossem atualizados.

Ray Lionfang
fonte
0

Se você tiver referências de chave estrangeira para a mesma tabela mais de uma vez, poderá usar InverseProperty

Algo assim-

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

Para mim (usando o Visual Studio 2017 e o modelo de banco de dados primeiro no Entity Framework 6.1.3), o problema foi embora depois de reiniciar o Visual Studio e Rebuilding.

neuronz
fonte
Isso não parece uma resposta definitiva para a pergunta, pois você não explica a causa. Deve ser colocado como um comentário.
Ibo
0

No meu caso, meus dados de método de propagação ainda estavam chamando uma coluna da tabela que havia sido descartada em uma migração anterior. Verifique novamente seus mapeamentos se estiver usando o Automapper.

SauerTrout
fonte
0

No meu caso, já tenho um banco de dados (primeiro banco de dados). Graças a todos os comentários aqui, encontrei minha solução:

As tabelas devem ter o relacionamento, mas o nome das colunas deve ser diferente e adicionar o atributo ForeignKey.

[ForeignKey ("PrestadorId")] public virtual AwmPrestadoresServicios Colaboradores {get; conjunto; }

Ou seja, PRE_ID é PK, mas FK na outra tabela é PRESTADOR_ID, então funciona. Graças a todos os comentários aqui encontrei minha solução. EF trabalha de maneiras misteriosas.

Mauricio molina
fonte
0

Se você tiver esse problema com uma propriedade de navegação na mesma tabela, terá que alterar o nome de nossa propriedade.

Por exemplo :

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

Você terá que mudar AncestorIdpara PersonId.

Parece que EF está tentando criar uma chave ParentIdporque não conseguiu encontrar uma tabela chamada Ancestral ...

EDIT: Esta é uma correção para o banco de dados primeiro!

Pierre
fonte