Как использовать существующее перечисление с Entity Framework DB First

Я использую Entity Framework 5, сначала БД. Я знаю, как определить перечисление в моей модели и установить тип поля для этого перечисления.

Теперь у меня есть требование сопоставить поле MyField с перечислением, которое определено извне, то есть не в модели EF (OtherNamespace.MyEnum). Дизайнер не позволяет мне установить тип вне модели. Я попытался отредактировать файл edmx вручную, но это вызывает ошибку:

Ошибка 10016: Ошибка разрешения элемента «MyField». Сообщение об исключении: «Неразрешенная ссылка «OtherNamespace.MyEnum».».

OtherNamespace.MyEnum упоминается в моем проекте.

Как ты это делаешь?


person Shaul Behr    schedule 01.10.2013    source источник
comment
Вам нужно будет проделать дополнительную логику, чтобы получить это, вы можете поместить это в сеттер.   -  person Botonomous    schedule 01.10.2013
comment
@ Данбар, что ты имеешь в виду? Можете быть более конкретными?   -  person Shaul Behr    schedule 01.10.2013
comment
Как и в установщике свойств, установите несопоставленный экземпляр объекта, который вы действительно хотите установить.   -  person Botonomous    schedule 01.10.2013
comment
@Dunbar, который будет работать в локальном коде, но не будет работать в IQueryable<MyClass>, например. db.MyClasses.Where(x => x.MyField == OtherNamespace.MyEnum.Value2)   -  person Shaul Behr    schedule 01.10.2013
comment
Есть ли в реализуемом вами перечислении известные целочисленные представления для каждого значения перечисления?   -  person cbeckner    schedule 07.10.2013
comment
@cbeckner - да, это так   -  person Shaul Behr    schedule 07.10.2013


Ответы (1)


Это можно сделать, но для этого потребуется немного пожертвовать со стороны базы данных. Entity Framework (начиная с версии 5) поддерживает сопоставление поля с перечислением, но только для типов byte, sbyte, short, ushort, int, uint, long или ulong.

Предположим, что у нас есть следующая примерная таблица:

CREATE TABLE [People](
    [id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
    [Name] [varchar](50) NOT NULL,
    [Title] [int] NOT NULL
)

Title было объявлено как целое число. В реальной базе данных это может быть внешний ключ к таблице TitleTypes.

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

namespace Enumerations
{
    public enum TitleEnum
    {
        Mr,
        Mrs,
        Dr,
        None
    }
}

Если мы импортируем таблицу People в EDMX, мы можем щелкнуть правой кнопкой мыши столбец Title и Преобразовать в Enum.

Преобразовать в перечисление

Это вызовет диалоговое окно, позволяющее нам указать имя для перечисления в EDMX ModelStore, определить любые значения для перечисления ИЛИ связать с внешним перечислением через Внешний тип ссылки.

Присвойте ему имя типа TitleEnum, установите флажок Ссылка на внешний тип и введите Enumerations.TitleEnum в соответствующем поле. Нажмите OK, и он свяжет столбец с внешним перечислением.

Примечание.

  • Хотя оба называются TitleEnum, это действует как переход к внешнему перечислению
  • Тип вашего столбца и внешнего перечисления ДОЛЖНЫ совпадать

Связывание перечисления

Теперь, когда мы создаем нового человека, мы можем использовать перечисление, и оно будет переведено в его представление Int.

Data.ScratchEntities context = new Data.ScratchEntities();
Data.Person person = new Data.Person();
person.Name = "Jane Smith";
//Note the use of the external enumeration here
person.Title = Enumerations.TitleEnum.Mrs;
context.People.Add(person);
context.SaveChanges();

Intellisense

person cbeckner    schedule 07.10.2013
comment
Спасибо за прекрасно документированный ответ. Но это не работает для меня. Все в порядке до последнего шага, но я получаю ошибку компилятора: невозможно преобразовать исходный тип Enumerations.TitleEnum в целевой тип MyNamespace.TitleEnum. Что я делаю неправильно? Может быть, это потому, что мой базовый тип byte, а не int? - person Shaul Behr; 07.10.2013
comment
да. Тип столбца и базовый тип для перечисления должны совпадать, чтобы можно было выполнять неявное преобразование из одного в другое. - person cbeckner; 08.10.2013
comment
Столбец в db представляет собой tinyint, который сопоставляется с байтом...? И если бы это было так, явное приведение должно работать, но это не так. - person Shaul Behr; 08.10.2013
comment
Насколько мне известно, при сопоставлении перечисления с перечислением невозможно явно указать тип при установке значения. Что ДЕЙСТВИТЕЛЬНО работает в этой ситуации, так это оставить определение типа EF для этого поля как byte, и когда вы устанавливаете значение из перечислений, приведите значение перечисления к соответствующему типу: td.Title = (byte)Enumerations.TitleEnum.Mr; - person cbeckner; 08.10.2013
comment
Все еще не имеет смысла. На снимке экрана видно, что Intellisense автоматически выбирает Enumerations.TitleEnum для назначения переменной типа MyNamespace.TitleEnum. Мой компилятор даже не принимает его, не говоря уже о Intellisense. Если я посмотрю на сгенерированный код, MyNamespace.TitleEnum — это просто пустой тип перечисления. Возможно, это проблема с моим шаблоном генерации кода? Как выглядит ваш сгенерированный код? - person Shaul Behr; 08.10.2013
comment
Когда вы преобразовали в Enum в EDMX, указали ли вы внешнее перечисление? Пытаясь воспроизвести ваши ошибки, когда я удаляю ссылку, я получаю точное сообщение об ошибке, которое вы упомянули в первом комментарии выше. Вы можете отредактировать существующее отображение перечисления через браузер моделей в разделе «Типы перечислений» (извините, мне потребовался час, чтобы добраться туда, еще не пил кофе) - person cbeckner; 08.10.2013
comment
Да, я указал внешнее перечисление. Это не имеет никакого значения в сгенерированном коде - person Shaul Behr; 08.10.2013
comment
давайте продолжим это обсуждение в чате - person cbeckner; 08.10.2013
comment
Пинг - пожалуйста, проверьте чат - person Shaul Behr; 12.10.2013
comment
Идеально - я не знал об этом, поэтому я просто реализовал свойство, которое преобразовало мой int в перечисление на Get; и перечислить в int на наборе; который, казалось, работал ... ПОКА я не пытался использовать страницу редактирования с каркасом. Я мог отобразить выбранное перечисление с помощью метода EnumDropDownListFor() и моего нового свойства, но это не сработало, когда вы пришли к сохранению. Это работает отлично. Я предполагаю, что единственным недостатком является то, что если я обновлю таблицу базы данных и должен обновить edmx, но повторить вышеуказанный шаг должно быть относительно легко. (работает 20 секунд). - person Percy; 29.03.2015
comment
Для тех, кто хочет использовать одно и то же перечисление для свойств в нескольких классах (например, тип культуры), вам не нужно делать это каждый раз — на самом деле вы не можете! Вам просто нужно щелкнуть свойство в дизайнере edmx и выбрать тип из раскрывающегося списка в окне свойств. Это не было для меня очевидным, поэтому я решил прокомментировать и помочь всем, кто хочет это сделать. - person Percy; 29.03.2015
comment
убедитесь, что вы объявили тип перечисления, например: public enum LookupEnum: int {Value1 = 1, Value2 = 2} - person MaurGi; 17.07.2015
comment
Какой шрифт в вашей IDE? - person test; 10.06.2016
comment
Совет для тех, кто ошибается в пространстве имен или имени типа в своей внешней ссылке: вы можете исправить это с помощью обозревателя моделей (щелкните правой кнопкой мыши фон диаграммы EDMX, чтобы открыть это окно), развернув Enum Types, один раз щелкнув копию EDMX enum, затем в окне свойств, изменив внешний тип. Сохраните свой EDMX после, и он должен повторно сгенерировать ссылку на тип для любых свойств, использующих его в EDMX. - person Matt Arnold; 04.11.2019