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