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) такой подход будет максимально оправдан.