Entity Framework - nieprawidłowa nazwa kolumny „* _ID”


103

Zawęziłem to do problemu między Code First i Database first EF, ale nie jestem pewien, jak to naprawić. Postaram się mówić tak jasno, jak tylko potrafię, ale szczerze mówiąc, sam brakuje mi części zrozumienia. To jest Entity Framework 4.4

Odziedziczyłem projekt, w którym był używany Entity Framework, ale wiele rzeczywistych plików zostało usuniętych bez realnego sposobu na powrót. Ponownie dodałem EF (najpierw baza danych) i zreplikowałem konfigurację T4, wokół której został zbudowany projekt. Wygenerował wersje kodu wszystkich modeli baz danych i plik kodu DBContext.

Jeśli moje parametry połączenia wyglądają jak „normalne” parametry połączenia .NET, pojawia się błąd dotyczący nieprawidłowej kolumny. Nazwa „ProcessState_ID” nie istnieje. ProcessState_ID w ogóle nie znajduje się w bazie kodu, nie ma go w pliku EDMX ani w niczym. Wydaje się, że jest to automatyczna konwersja EF w zapytaniu.

Kiedy dopasowuję parametry połączenia do modelu Entity Framework, działa dobrze.

Teraz, próbując dopasować poprzedni kod do Entity Framework, chciałbym zachować „normalne” parametry połączenia .NET.

Mam więc tutaj dwa pytania: 1. Jaki jest dobry sposób przejścia od normalnych parametrów połączenia do parametrów połączenia EF w kodzie? 2. Czy jest tu inna poprawka, której nie widzę, aby zatrzymać błąd nieprawidłowej nazwy kolumny?


3
Dzieje się tak również, jeśli masz właściwość nawigacyjną z tylko akcesorium get:public virtual Person Person { get; }
Şafak Gür

Proszę zaznaczyć odpowiedź
Więzień ZERO

Odpowiedzi:


92

Sprawdź, czy masz jakieś kolekcje ICollections.

Odkryłem, że gdy masz kolekcję ICollection, która odwołuje się do tabeli i nie ma żadnej kolumny, którą mógłby znaleźć, tworzy ją, abyś spróbował nawiązać połączenie między tabelami. Dzieje się tak szczególnie w przypadku ICollection i zmusiło mnie do tego, by to rozgryźć.


44
Żeby wyjaśnić tę odpowiedź, ponieważ była ona najbardziej dokładna w mojej sytuacji (ale nie wiedziałem o tym, dopóki nie rozwiązałem problemu). Jeśli podczas pobierania tabeli wystąpił błąd związany z OtherTable_ID, przejdź do modelu OtherTable i upewnij się, że nie ma tam ICollection <Table>. Bez zdefiniowanej relacji platforma automatycznie przyjmie, że musisz mieć FK do OtherTable i utworzysz te dodatkowe właściwości w wygenerowanym SQL.
LUKE

15
EF zmarnował moje 4 godziny
Nitin S

2
@NitinSawant To wszystko? EF marnuje mi 4 godziny dziennie ze wszystkimi swoimi duplikatami i niepowiązanymi rekordami.
Jacob

@LUKE Twój komentarz mnie uratował. Tak bardzo cię kocham :)
Arad

1
@LUKE bohater EF, którego potrzebujemy, a nie bohater EF, na który zasługujemy. Kocham Cię.
Matthew Young

65

To jest późny wpis dla tych (takich jak ja), którzy nie od razu zrozumieli pozostałe 2 odpowiedzi.

Więc...

EF próbuje mapować na oczekiwaną nazwę z PARENT TABLES KEY-REFERENCE ... a ponieważ ... nazwa FOREIGN KEY została "zmieniona lub skrócona" w relacji CHILD TABLE w bazach danych ... otrzymałeś powyższy komunikat.

(ta poprawka może się różnić w zależności od wersji EF)

DLA MNIE NAPRAWIONO BYŁO:
DODAWANIE atrybutu „ForeignKey” do modelu

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
To zadziałało dla mnie. +1 za bycie jedynym miejscem, w którym znalazłem tę odpowiedź.
Jerry Benson-Montgomery

@Jerry Mam zdefiniowany klucz forign. Ale nadal wyszukuje rozszerzenie Category_Id. Wspomniałeś o poprawkach dla różnych wersji EF, prawda? używam EF 6.0. Jaka jest poprawka, którą canadopt?
Ajay Aradhya

@ ajay-aradhya Właściwie to osoba, która pierwotnie odpowiedziała, więzień-zero, skomentowała różne wersje EF.
Jerry Benson-Montgomery

@ JerryBenson-Montgomery nieważne! sprawiłem, że to zadziałało. To właśnie mapowanie „jeden do jednego” powodowało, że szukał *_ID. W tym odniesienie wsteczne działało dobrze.
Ajay Aradhya

1
Możesz również to naprawić, dodając częściową klasę metadanych, dzięki czemu nie będziesz musiał tego naprawiać podczas regeneracji. [MetadataType(typeof(MetaData))] public partial class Tour { public class MetaData { [ForeignKey(nameof(TourCategory))] public virtual TourCategory TourCategory { get; set; } } }
Carter Medlin

41

Święta krowa - po wielu godzinach prób w końcu to rozgryzłem.

Najpierw robię bazę danych EF6 i zastanawiałem się nad błędem „nieznana kolumna zakresu” - z jakiegoś powodu generował on nazwę tabeli podkreśloną nazwę kolumny i próbował znaleźć nieistniejącą kolumnę.

W moim przypadku jedna z moich tabel miała dwa odniesienia do kluczy obcych do tego samego klucza podstawowego w innej tabeli - coś takiego:

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

EF generował dziwne nazwy kolumn, takie jak Owners_AnimalID1iOwners_AnimalID2 , a następnie udał się do złamania.

Sztuczka polega na tym, że te mylące klucze obce muszą być zarejestrowane w EF przy użyciu Fluent API!

W kontekście głównej bazy danych Zastąp OnModelCreatingmetodę i zmień konfigurację jednostki. Najlepiej, abyś miał osobny plik, który rozszerza EntityConfigurationklasę, ale możesz to zrobić w tekście.

Jakkolwiek to zrobisz, musisz dodać coś takiego:

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

Dzięki temu EF (być może) zacznie działać zgodnie z oczekiwaniami. Bum.

Ten sam błąd pojawi się również, jeśli użyjesz powyższego z kolumną dopuszczającą wartość null - po prostu użyj .HasOptional()zamiast .HasRequired().


Oto link, który umieścił mnie ponad garbem:

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

A potem pomocna jest dokumentacja Fluent API, zwłaszcza przykłady kluczy obcych:

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

Możesz również umieścić konfiguracje na drugim końcu klucza, jak opisano tutaj:

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

Mam teraz kilka nowych problemów, ale to była ogromna luka koncepcyjna, której brakowało. Mam nadzieję, że to pomoże!


1
Wielkie dzięki ... Miałem ten sam problem.
Sachin Parashar

U mnie też to zadziałało, dodano podobne linie kodu w pliku mapy: builder.HasOne(item => item.LogicalShipment).WithMany(s => s.Items).HasForeignKey(item => item.LogicalShipmentId).IsRequired();
DaminiVyas

14

Założenia:

  • Table
  • OtherTable
  • OtherTable_ID

Teraz wybierz jeden z tych sposobów:


ZA)

Usunąć ICollection<Table>

Jeśli masz jakiś błąd związany z OtherTable_IDpobieraniem Table, przejdź do swojego OtherTablemodelu i upewnij się, że go tam nie ma ICollection<Table>. Bez zdefiniowanej relacji platforma automatycznie przyjmie, że musisz mieć FK do OtherTable i utworzysz te dodatkowe właściwości w wygenerowanym SQL.

Cała zasługa tej odpowiedzi należy do @LUKE. Powyższa odpowiedź to jego komentarz pod @drewid answer. Myślę, że jego komentarz jest tak czysty, że przepisałem go jako odpowiedź.


B)

  • Dodaj OtherTableIddoTable

i

  • Zdefiniować OtherTableIdw Tablebazie danych w

1
Taka genialna odpowiedź!
Arad

Ta odpowiedź rzeczywiście szybko uratowała się w ciągu dnia. i dzięki LUKE'owi przeczytałem jego komentarz. Chociaż @drewid znalazł się na końcu łańcucha odpowiedzi, ale był wspaniały i był potrzebny większości w tej sytuacji.
Div Tiwari

3

W moim przypadku nieprawidłowo zdefiniowałem klucz podstawowy składający się z dwóch kluczy obcych, takich jak ten:

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

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

Pojawił się błąd „nieprawidłowa nazwa kolumny Bar_ID”.

Określenie złożonego klucza podstawowego poprawnie rozwiązało problem:

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

...

3

U mnie przyczyną tego zachowania był problem ze zdefiniowanym mapowaniem za pomocą Fluent API. Miałem 2 powiązane typy, gdzie typ A miał opcjonalny obiekt typu B, a typ B miał wiele obiektów A.

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

Zdefiniowałem mapowanie z płynnym interfejsem API w następujący sposób:

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

Problem w tym, że ten typ B miał właściwość nawigacyjną List<A> , więc w rezultacie miałemSQLException Invalid column name A_Id

Dołączyłem Visual Studio Debug do EF DatabaseContext.Database.Log, aby wyprowadzić wygenerowany kod SQL do VS Output-> Debug window

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

Wygenerowany SQL miał 2 relacje z tabeli B -> jedną z poprawnym identyfikatorem, a drugą z rozszerzeniem A_Id

Problem polegał na tym, że tego nie dodałem B.List<A> właściwości nawigacji do mapowania.

Tak więc w moim przypadku musiało być poprawne mapowanie:

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

2

W moim przypadku przyczyną tego problemu był brak ograniczenia klucza OBCEGO w zmigrowanej bazie danych. Zatem istniejąca wirtualna kolekcja ICollection nie została pomyślnie załadowana.


1

Miałem też ten problem i wygląda na to, że jest kilka różnych przyczyn. Dla mnie była to właściwość id, która została błędnie zdefiniowana jako int zamiast long w klasie nadrzędnej, która zawierała obiekt nawigacyjny. Pole id w bazie danych zostało zdefiniowane jako bigint, co odpowiada długości w języku C #. Nie spowodowało to błędu kompilacji, ale spowodowało ten sam błąd w czasie wykonywania, co 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

Dla mnie problem polega na tym, że dwukrotnie zamapowałem tabelę w mojej aplikacji - raz przez Code First, raz przez Database First.

Usunięcie jednego z nich rozwiązuje problem w moim przypadku.


1

U mnie stało się to z powodu problemów z pluralizacją EF. W przypadku tabel, które kończą się czymś w rodzaju „-Status”, EF uważa, że ​​liczba pojedyncza to „-Statu”. Zmiana nazwy jednostki i tabeli DB na „-StatusTypes” naprawiła ten problem.

W ten sposób nie trzeba zmieniać nazw modeli jednostek za każdym razem, gdy są aktualizowane.


0

Jeśli masz odniesienia do kluczy obcych do tej samej tabeli więcej niż raz, możesz użyć InverseProperty

Coś takiego-

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

0

U mnie (korzystam z programu Visual Studio 2017 i modelu w pierwszej kolejności bazy danych w ramach Entity Framework 6.1.3) problem zniknął po ponownym uruchomieniu programu Visual Studio i odbudowie.


Nie wygląda to na ostateczną odpowiedź na pytanie, ponieważ nie wyjaśniasz przyczyny. Należy to umieścić jako komentarz.
Ibo

0

W moim przypadku dane metody seed nadal wywoływały kolumnę tabeli, która została usunięta podczas poprzedniej migracji. Sprawdź dokładnie swoje mapowania, jeśli używasz Automapper.


0

W moim przypadku mam już bazę danych (Baza danych jest pierwsza). Dzięki wszystkim komentarzom tutaj znalazłem swoje rozwiązanie:

Tabele muszą mieć relację, ale nazwy kolumn muszą być inne i dodać atrybut ForeignKey.

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

Oznacza to, że PRE_ID to PK, ale FK w drugiej tabeli to PRESTADOR_ID, wtedy działa. Dzięki wszystkim komentarzom tutaj znalazłem swoje rozwiązanie. EF działa w tajemniczy sposób.


0

Jeśli masz ten problem z właściwością nawigacji w tej samej tabeli, będziesz musiał zmienić nazwę naszej usługi.

Na przykład :

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

Będziesz musiał zmienić AncestorIdnaPersonId .

Wygląda na to, że EF próbuje utworzyć klucz, ParentIdponieważ nie mógł znaleźć tabeli o nazwie Ancestor ...

EDYCJA: To jest pierwsza poprawka dla bazy danych!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.