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?
źródło
public virtual Person Person { get; }
Odpowiedzi:
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źć.
źródło
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; } }
źródło
Category_Id
. Wspomniałeś o poprawkach dla różnych wersji EF, prawda? używam EF 6.0. Jaka jest poprawka, którą canadopt?*_ID
. W tym odniesienie wsteczne działało dobrze.[MetadataType(typeof(MetaData))] public partial class Tour { public class MetaData { [ForeignKey(nameof(TourCategory))] public virtual TourCategory TourCategory { get; set; } } }
Ś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:
EF generował dziwne nazwy kolumn, takie jak
Owners_AnimalID1
iOwners_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
OnModelCreating
metodę i zmień konfigurację jednostki. Najlepiej, abyś miał osobny plik, który rozszerzaEntityConfiguration
klasę, 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!
źródło
builder.HasOne(item => item.LogicalShipment).WithMany(s => s.Items).HasForeignKey(item => item.LogicalShipmentId).IsRequired();
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_ID
pobieraniemTable
, przejdź do swojegoOtherTable
modelu i upewnij się, że go tam nie maICollection<Table>
. Bez zdefiniowanej relacji platforma automatycznie przyjmie, że musisz mieć FK do OtherTable i utworzysz te dodatkowe właściwości w wygenerowanym SQL.B)
OtherTableId
doTable
i
OtherTableId
wTable
bazie danych wźródło
W moim przypadku nieprawidłowo zdefiniowałem klucz podstawowy składający się z dwóch kluczy obcych, takich jak ten:
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 }); ...
źródło
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:
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
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:
źródło
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.
źródło
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; } }
źródło
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.
źródło
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.
źródło
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; }
źródło
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.
źródło
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.
źródło
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.
źródło
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ć
AncestorId
naPersonId
.Wygląda na to, że EF próbuje utworzyć klucz,
ParentId
ponieważ nie mógł znaleźć tabeli o nazwie Ancestor ...EDYCJA: To jest pierwsza poprawka dla bazy danych!
źródło