Entity Framework - недопустимое имя столбца "* _ID"


101

Я сузил это до некоторой проблемы между Code First и Database first EF, но я не уверен, как это исправить. Я постараюсь быть как можно более ясным, но, честно говоря, мне сам не хватает некоторого понимания. Это Entity Framework 4.4

Я унаследовал проект, в котором использовалась Entity Framework, но многие фактические файлы были удалены без возможности вернуться назад. Я повторно добавил EF (сначала базу данных) и реплицировал настройку T4, вокруг которой был построен проект. Он сгенерировал версии кода всех моделей баз данных и файл кода DBContext.

Если моя строка подключения выглядит как «обычная» строка подключения .NET, я получаю сообщение об ошибке о недопустимом столбце Имя «ProcessState_ID» не существует. ProcessState_ID вообще отсутствует в базе кода, его нет в файле EDMX или в чем-то еще. Это похоже на автоматическое преобразование EF в запросе.

Когда я заставляю строку подключения соответствовать модели Entity Framework, она работает нормально.

Теперь, пытаясь сопоставить предыдущий код с Entity Framework, я хотел бы сохранить «обычную» строку подключения .NET.

Итак, у меня есть два вопроса: 1. Как лучше всего перейти от обычной строки подключения к строке подключения EF в коде? 2. Есть ли еще одно исправление, которое я не вижу, чтобы остановить ошибку недопустимого имени столбца?


3
Это также происходит, если у вас есть свойство навигации только с аксессором get:public virtual Person Person { get; }
Шафак Гюр,

Отметьте, пожалуйста, ответ
Заключенный ZERO

Ответы:


90

Проверьте, есть ли у вас ICollections.

Я выяснил, что когда у вас есть ICollection, который ссылается на таблицу, и нет столбца, который он может определить, он создает один, чтобы вы попытались установить связь между таблицами. В частности, это происходит с ICollection и заставляет меня «бить», пытаясь понять это.


43
Просто чтобы прояснить этот ответ, потому что он был наиболее точным для моей ситуации (но я не знал этого до тех пор, пока не понял свою проблему). Если при получении таблицы у вас возникла ошибка, связанная с OtherTable_ID, перейдите к своей модели OtherTable и убедитесь, что у вас нет ICollection <Table>. Без определенной связи платформа автоматически предположит, что у вас должен быть FK для OtherTable, и создаст эти дополнительные свойства в сгенерированном SQL.
ЛУКА

15
EF потратил впустую мои 4 часа
Nitin S

2
@NitinSawant Вот и все? EF зря тратит мне 4 часа в день со всеми своими дубликатами и неприложенными записями.
Джейкоб

@LUKE Ваш комментарий спас меня. Я так сильно тебя люблю :)
Амир Хоссейн Ахмади

1
@LUKE - герой EF, который нам нужен, а не герой EF, которого мы заслуживаем. Я тебя люблю.
Мэтью Янг

63

Это поздняя запись для тех (вроде меня), которые не сразу поняли два других ответа.

Так...

EF пытается сопоставить ОЖИДАЕМУЮ имя из РОДИТЕЛЬСКИХ ТАБЛИЦ KEY-REFERENCE ... и поскольку ... имя FOREIGN KEY было "изменено или сокращено" в отношениях CHILD TABLE баз данных ... вы получите сообщение выше.

(это исправление может отличаться в зависимости от версии EF)

ДЛЯ МЕНЯ ИСПРАВЛЕНИЕМ БЫЛО:
ДОБАВЛЕНИЕ атрибута "ForeignKey" в модель.

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
Это сработало для меня. +1 за то, что это единственное место, где я нашел этот ответ.
Джерри Бенсон-Монтгомери,

@Jerry Я определил чужой ключ. Но все же он ищет свой Category_Id. Вы упомянули об исправлениях для разных версий EF, верно? Я использую EF 6.0. Какое исправление я могу принять?
Аджай Арадхья

@ ajay-aradhya На самом деле, это был человек, который первоначально ответил, нулевой заключенный, который сделал комментарий о различных версиях EF.
Джерри Бенсон-Монтгомери

@ ДжерриБенсон-Монтгомери, да ладно! я заставил это работать. Это было сопоставление «один к одному», которое заставляло его искать *_ID. В том числе обратная ссылка работала нормально.
Аджай Арадхья

1
Вы также можете исправить это, добавив частичный класс метаданных, чтобы вам не пришлось исправлять это при регенерации. [MetadataType(typeof(MetaData))] public partial class Tour { public class MetaData { [ForeignKey(nameof(TourCategory))] public virtual TourCategory TourCategory { get; set; } } }
Картер Медлин

40

Святая корова - после многих часов попыток я наконец понял это.

Сначала я делаю базу данных EF6, и мне было интересно узнать об ошибке «неизвестный столбец степени» - по какой-то причине она генерировала имя столбца подчеркивания имени таблицы и пыталась найти несуществующий столбец.

В моем случае в одной из моих таблиц было две ссылки внешнего ключа на один и тот же первичный ключ в другой таблице - примерно так:

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

EF производило некоторое странное имя столбца , как Owners_AnimalID1и Owners_AnimalID2затем продолжил ломать себя.

Уловка здесь в том, что эти запутанные внешние ключи необходимо зарегистрировать в EF с помощью Fluent API!

В контексте основной базы данных переопределите OnModelCreatingметод и измените конфигурацию объекта. Желательно, чтобы у вас был отдельный файл, расширяющий EntityConfigurationкласс, но вы можете сделать это встроенным.

В любом случае вам нужно будет добавить что-то вроде этого:

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

И с этим EF (возможно) начнет работать так, как вы ожидаете. Бум.

Кроме того, вы получите ту же ошибку, если используете указанное выше со столбцом, допускающим значение NULL - просто используйте .HasOptional()вместо .HasRequired().


Вот ссылка, которая меня сбила с толку:

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

И тогда вам помогут документы Fluent API, особенно примеры внешних ключей:

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

Вы также можете поместить конфигурации на другой конец ключа, как описано здесь:

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

Сейчас я сталкиваюсь с некоторыми новыми проблемами, но это был огромный концептуальный пробел, которого не хватало. Надеюсь, поможет!


1
Большое спасибо .. У меня была такая же проблема.
Сачин Парашар

Это сработало и у меня, добавив похожие строки кода в файл карты: builder.HasOne(item => item.LogicalShipment).WithMany(s => s.Items).HasForeignKey(item => item.LogicalShipmentId).IsRequired();
DaminiVyas

14

Предположения:

  • Table
  • OtherTable
  • OtherTable_ID

Теперь выберите один из следующих способов:


А)

удалять ICollection<Table>

Если у вас есть какая-то ошибка, связанная с OtherTable_IDполучением Table, перейдите к своей OtherTableмодели и убедитесь, что у вас ICollection<Table>там нет. Без определения отношения платформа автоматически предполагает, что у вас должен быть FK для OtherTable, и создает эти дополнительные свойства в сгенерированном SQL.

Вся заслуга в этом ответе принадлежит @LUKE. Вышеупомянутый ответ - это его комментарий под ответом @drewid. Я думаю, что его комментарий настолько чистый, что я переписал его как ответ.


Б)

  • Добавить OtherTableIdвTable

и

  • Определение OtherTableIdв Tableбазе данных в

1
Такой блестящий ответ!
Амир Хоссейн Ахмади

Этот ответ действительно спасен днём быстро. и благодаря ЛЮКУ, я прочитал его комментарий. Хотя @drewid занял последнее место в цепочке ответов, но он был превосходным и был необходим большинству в этой ситуации.
Div Tiwari,

3

В моем случае я неправильно определял первичный ключ, состоящий из двух внешних ключей, например:

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

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

Ошибка, которую я получал, была «недопустимое имя столбца Bar_ID».

Указание составного первичного ключа правильно устранило проблему:

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

...

3

Для меня причиной такого поведения была проблема с определенным сопоставлением с Fluent API. У меня было 2 связанных типа, где тип A имел необязательный объект типа B, а тип B имел много объектов A.

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

Я определил отображение с помощью свободного API следующим образом:

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

Но проблема заключалась в том, что этот тип B имел свойство навигации List<A>, поэтому в результате у меня былоSQLException Invalid column name A_Id

Я прикрепил Visual Studio Debug к EF DatabaseContext.Database.Log для вывода сгенерированного SQL в VS Output-> Окно отладки

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

И сгенерированный SQL имел 2 отношения из таблицы B -> одно с правильным идентификатором, а другое с A_Id

Проблема заключалась в том, что я не добавил это B.List<A>свойство навигации в отображение.

Вот как в моем случае должно было быть правильное отображение:

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

2

В моем случае причиной этой проблемы было отсутствие ограничения FOREIGN KEY в перенесенной базе данных. Таким образом, существующая виртуальная коллекция ICollection не была загружена успешно.


1

У меня тоже была эта проблема, и кажется, что есть несколько разных причин. Для меня это было свойство id, ошибочно определенное как int вместо long в родительском классе, содержащем объект навигации. Поле id в базе данных было определено как bigint, что соответствует long в C #. Это не вызвало ошибки времени компиляции, но вызвало ту же ошибку времени выполнения, что и 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

Для меня проблема в том, что таблица была отображена в моем приложении дважды - один раз через Code First, второй раз через Database First.

Удаление любого из них решает проблему в моем случае.


1

Для меня это произошло из-за проблем с множественным числом EF. Для таблиц, которые заканчиваются чем-то вроде «-Status», EF считает, что это единственное число «-Statu». Изменение имени сущности и таблицы БД на "-StatusTypes" исправило это.

Таким образом, вам не нужно будет переименовывать модели сущностей каждый раз при их обновлении.


0

Если у вас есть ссылки внешнего ключа на одну и ту же таблицу более одного раза, вы можете использовать InverseProperty

Что-то вроде этого-

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

0

Для меня (с использованием Visual Studio 2017 и модели «сначала база данных» в Entity Framework 6.1.3) проблема исчезла после перезапуска Visual Studio и перестройки.


Это не выглядит окончательным ответом на вопрос, поскольку вы не объясняете причину. Это следует поставить в качестве комментария.
Ibo

0

В моем случае данные моего начального метода по-прежнему вызывали столбец таблицы, который был удален при предыдущей миграции. Дважды проверьте свои сопоставления, если вы используете Automapper.


0

В моем случае у меня уже есть база данных (первая база данных). Благодаря всем комментариям я нашел свое решение:

Таблицы должны иметь взаимосвязь, но имена столбцов должны быть разными и содержать атрибут ForeignKey.

[ForeignKey ("PrestadorId")] общедоступный виртуальный AwmPrestadoresServicios Colaboradores {получить; устанавливать; }

То есть PRE_ID - это PK, но FK в другой таблице - PRESTADOR_ID, тогда он работает. Благодаря всем комментариям здесь я нашел свое решение. EF работает загадочным образом.


0

Если у вас возникла проблема со свойством навигации в той же таблице, вам придется изменить имя нашего свойства.

Например :

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

Вы должны изменить AncestorIdдляPersonId .

Похоже, EF пытается создать ключ ParentId потому что не может найти таблицу с именем Ancestor ...

РЕДАКТИРОВАТЬ: это сначала исправление для базы данных!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.