Pull to refresh

Code-first в Entity Framework

Reading time4 min
Views56K
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) такой подход будет максимально оправдан.
Tags:
Hubs:
Total votes 55: ↑46 and ↓9+37
Comments12

Articles