Подтвердить что ты не робот

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

Я сузил это до некоторой проблемы между первым кодом и первым 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. Есть ли другое исправление здесь, которое я не вижу, чтобы остановить неправильную ошибку имени столбца?

4b9b3361

Ответ 1

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

То, что я понял, - это когда у вас есть ICollection, который ссылается на таблицу, и нет столбца, который он может определить, он создает один для вас, чтобы попытаться установить соединение между таблицами. Это особенно происходит с ICollection и заставило меня "батти" попытаться понять это.

Ответ 2

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

Итак...

EF пытается сопоставить ОЖИДАЕМОЕ имя из КЛЮЧА-РЕФЕРЕНЦИИ РОДИТЕЛЕЙ... а так как... имя 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; }
}

Ответ 3

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

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

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

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

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

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

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

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

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

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

Кроме того, вы получите ту же самую ошибку, если используете вышеописанный столбцы с нулевым значением - просто используйте .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

И затем, API-интерфейсы 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.

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

Ответ 4

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

  • Table
  • OtherTable
  • OtherTable_ID

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


A)

Удалить ICollection<Table>

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

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


B)

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

а также

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

Ответ 5

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

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 });

...

Ответ 6

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

Ответ 7

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

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

Ответ 8

Для меня причина этого поведения была из-за проблемы с определенным отображением с 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> навигации B.List<A> в отображение.

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

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

Ответ 9

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

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

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

Ответ 10

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

Ответ 11

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

Ответ 12

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