Пользователь
0,0
рейтинг
11 июня 2011 в 16:53

Разработка → Code-first в Entity Framework

.NET*
Into

Под .NET существует две родных ORM, разрабатываемых и поддерживаемых Microsoft, — Entity Framework и Linq2Sql. Однако Entity Framework продолжает развиваться внушительными темпами, а про будущее Linq2Sql ничего толком неизвестно.

Entity Framework предлагает удобный дизайнер, огромное количество вариантов маппинга, автогенерацию классов-моделей, но на все это есть жирный минус – гигантские и раздутые сгенерированные классы, которые к тому же нельзя изменять вручную – ибо при каждом изменении модели в дизайнере, все будет пересоздано заново. Сравните это с чистыми классами, и добавленными к ним атрибутами, как в Linq2Sql, и вы поймете, почему такое количество людей заявляет о легковесности Linq2Sql и монструозности EF.

Конечно, каждая проблема имеет решение, и эта не исключение. Частичные классы позволят добавить нужный функционал, а специально созданные классы с правилами валидации, помеченные атрибутом [MetadataType], дадут возможность использовать атрибуты валидации для классов-моделей. Но вместе это получается не очень красиво – размазанные по проекту классы, увеличение их количества, и все та же сложность в поддержке.

Не стоит также забывать об условиях работы классов-моделей: они должны либо наследоваться от EntityObject или реализовывать интерфейсы EntityWithKey, IEntityWithChangeTracker и IEntityWithRelationships

Так что же делать тем, кто хочет получить максимально простые классы для работы внутри ORM?

РОСО и Code-First

Впервые поддержка РОСО(Plain Old CLR Objects), т.е работы с простыми классами, как с моделями появилась в EF 4.

Примечание

Несмотря на заявленную поддержку в Visual Studio SP1, мне для корректной работы все-таки пришлось установить Visual Studio Tools for SQL Server Compact 4 и EF Code First Package

Например, вот такой класс
public class Author
        {
            public int AuthorID { get; set; }
            public string Email { get; set; }
            public string Name { get; set; }
        }

Описывает полнофункциональную сущность «автор», причем он не нуждается ни в базовом классе, ни в интерфейсах, ни в атрибутах или метадананных.

Простейшая же точка входа будет выглядеть так:
public class Library : DbContext
        {
            public DbSet<Author> Authors { get; set; }
        }

И все! Сразу после создания объекта Library, вы можете работать с ним, используя все преимущества EF.

Code-First – новая возможность, стоящая в одном ряду с Model-First и Database-First. Теперь можно сначала написать код, описывающий классы-модели, а потом фреймворк автоматически создаст БД по такому коду.
Самое приятное, что виды отношений будут распознаны – достаточно определить просто ссылки на объекты для 1:1, ICollection для отношения 1:n, и взаимные ICollection для m:n. В этом случае промежуточная таблица также создастся автоматически. Для обеспечения «ленивой» загрузки хватит ключевого слова virtual в определении свойства.

Также полностью поддерживаются атрибуты из пространства имен System.ComponentModel.DataAnnotations

Основные из них:
• [Key] – указывает на то, что данное свойство будет ключевым.
• [NotMapped] – не отображать свойство на колонки в БД.
• [Column(“columnName”, TypeName=”typeName”] – указывает колонку в БД, на которую отображается поле и его тип. Полезно когда в классе есть свойство типа byte[], хранящий, например рисунок, а в базе это отобразится на специальный тип image.
UPD Однако нельзя указать подмножество типа таким образом: например для строк по умолчанию в базе выбирается тип nvarchar(MAX) и с помощью этого атрибута нельзя явно указать длину поля nvarchar(30)
• [MinLength], [MaxLength], [Required] и другие для обеспечения проверки данных

Code-First заточен под работу с новой версией SQL Server CE 4.0. Поддержка этой базы данных включена в MVC3, и некоторые люди уже переводят сайты на работу с такой БД, а не стандартным SQL Express.

По умолчанию, генератор БД пытается создать SQL Express базу данных, если у него не получается – тогда SQL Server CE. Это поведение легко переопределяется в app.config
  <connectionStrings>
    <add name="Library" 
         connectionString="Data Source=Library.sdf" 
         providerName="System.Data.SqlServerCe.4.0"/>
  </connectionStrings>

Обратите внимание, что имя строки соединения должно совпадать с именем класса-точки доступа(DbContext).

Также можно определить стратегию создания базы данных (первичная генерация или обновление). Всякая стратегия – это класс, реализующий интерфейс IDatabaseInitializer, т.е. можно определить свою стратегию, заносящую какие-либо данные в БД в период активной разработки программы.
Предустановленные стратегии – CreateDatabaseIfNotExists (создавать БД, если ее нет), DropCreateDatabaseAlways (БД всегда будет удаляться и пересоздаваться), DropCreateDatabaseIfModelChanges (пересоздается при изменениях в модели)

Изменяется стратегия работы с БД вызовом
Database.SetInitializer(new DropCreateDatabaseAlways());

При создании БД фреймворк создает еще одну, служебную таблицу EdmMetadata, в которой хранится хеш-отпечаток модели на момент создания. Это неудобно при активной разработке БД и классов, но есть решение – перегрузка метода OnModelCreating класса DbContext.
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
            }


Вообще, Conventions это довольно мощная вещь. Они позволяют конфигурировать отображение свойств на БД на основе разнообразных признаков, подключать/отключать пространства имен и многое другое. Подробнее о них можно почитать здесь

Code-First действительно предоставляет много возможностей по управлению кодом моделей, максимально удобным способом для вас. Я считаю, что в особенности для небольших проектов, как и для мобильных устройств(да, SQL Server CE 4.0 будет поддерживаться в Windows Phone Mango) такой подход будет максимально оправдан.
Иван Манжос @Sirix
карма
18,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (12)

  • +1
    Спасибо за статью
    • +5
      Пожалуйста, рад стараться!
  • 0
    Скажите плз, CodeFirst уже поборол децкие болезни роста? Например использование GUID в качестве PK? А то раньше с этим вылазил целый ворох проблем.
    • 0
      Да, GUID полностью может использоваться в качестве РК, единственное ограничение, что при работе с SQL Server CE 4.0 не поддерживается использование автогенерации на стороне сервера. То есть вот такой код
      public class Tag
              {
                  [Key]
                  [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
                  public Guid TagID { get; set; }
                  public string TagName { get; set; }
              }
      

      не будет корректно работать, надо явно указывать GUID перед записью в БД:
      Tag t1 = new Tag {TagName = ".net", TagID = Guid.NewGuid()};
      
      • 0
        А указать явно значение по-умолчанию, как, например, «newid()», нельзя?
    • 0
      Ещё не поборол — enum'ы.
      Нет миграций — только recreate database.
      Нельзя менять конвеншены.

      С какого перепуга они назвали это релизом, я не понимаю.
      • 0
        Да, отсутствие миграций сильно напрягает. Пожалуй, самая неудобная вещь, приходится руками менять все
      • +1
        А кто сказал, что миграции там должны быть? Это ORM, а не migration-фреймворк. Юзайте Migrator.NET.

        А в целом, на самом деле, много чего не поборол.
  • 0
    Описывает полнофункциональную сущность «автор», причем он не нуждается ни в базовом классе, ни в интерфейсах, ни в атрибутах или метадананных.

    Можно сказать, что не нуждается. Однако не всех может устроить для Email и Name столбцы типа NVARCHAR(MAX). Думаю, об этом имеет смысл упомянуть, чтобы не создавалось впечатление сказки ;)
    Вообще, Conventions это довольно мощная вещь.… Подробнее о них можно почитать здесь

    Строго говоря, в текущем релизе нет официальной поддержки своих Conventions — только возможность отключения стандартных.

    P.S. Не подумайте, что я противник EF 4.1 — очень даже неплохой шаг вперед. Просто не хочу, чтобы у кого-нибудь были завышенные ожидания.
    • 0
      Добавил замечание насчет маппинга типов. Спасибо!
      • 0
        Я имел в виду немного другое — что без атрибутов или ModelBuilder в реальном приложении не обойтись.

        P.S. Для задания длины строки есть атрибут StringLength.
  • +2
    > «Вообще, Conventions это довольно мощная вещь.… Подробнее о них можно почитать здесь»
    Conventions — по определению очень мощная вещь. Это именно то, что позволяет в 90% случаев не писать тривиального кода. Именно поэтому такие тулзы как, скажем, FluentNHibernate или AutoMapper так юзабельны.

    По теме — CF — хороший шаг вперед, но, честно говоря, EF сам по себе содержит детские проблемы.
    Например, до сих пор нет нормального Lazy Loading. Решается только собственной реализацией Dynamic Proxy. Ну и о таких фичах как кэш 2-го уровня, вообще говорить не приходится. Собственно, посмотрим что будет дальше.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.