Как известно, в Entity Framework действует ряд соглашений для Code First. Изменить их можно с помощью аннотации данных (Data Annotations) или через интерфейс Fluent API. Их можно использовать совместно. В конечном счете, информация о маппинге собирается в порядке Fluent API, Аннотации данных, а затем - соглашения. В последнее время все большую популярность набирает удобный и понятный интерфейс Fluent. С помощью него посмотрим, каким образом можно кастомизировать маппинг.
Сразу оговорюсь, что моей целью является показать каким образом можно настраивать маппинг с fluent-интерфейсом, а не как делается сам маппинг.
Для начала создадим пару объектов, с которыми будем работать дальше. Не будем усложнять и нагружать классы какой-либо бизнес-логикой:
public class Product { public int Id { get; set; } public string Name { get; set; } public Category Category { get; set; } } public class Category { public int Id { get; set; } public string Name { get; set; } public ICollection<Product> Products { get; set; } }
Теперь создадим контекст базы данных:
public class ExampleContext : DbContext { public DbSet<Product> Products { get; set; } public DbSet<Category> Categories { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { // настройка параметров таблицы через Fluent API } }
Как указано в комментарии, настройка параметров генерируемой таблицы производится в переопределенном методе OnModelCreating соответствующего контекста базы данных. Все настройки аккумулируются в экземпляре DbModelBuilder - modelBuilder, который передается в метод в качестве параметра. А дальше можно поступать по-разному.
Первый способ
Первый способ заключается в том, чтобы каждую отдельную настройку производить через методы DbModelBuilder Entity
protected override void OnModelCreating(DbModelBuilder modelBuilder) { // настройка параметров таблицы через Fluent API modelBuilder.Entity<Product>() .ToTable("Products"); modelBuilder.Entity<Product>() .HasKey(p => p.Id); modelBuilder.Entity<Product>() .Property(p => p.Name) .HasColumnName("Name") .HasMaxLength(100) .IsRequired(); modelBuilder.Entity<Category>() .ToTable("Categories"); modelBuilder.Entity<Category>() .Property(c => c.Name) .HasColumnName("CategoryName"); }
Этот способ хорошо подойдет в том случае, когда настроек совсем немного и в основном подойдут параметры, полученные на основе соглашений. В противном случае, метод OnModelCreating разрастается до огромных размеров и превращается в кашу. Особенно напрягает необходимость каждый раз для настройки какого-либо параметра маппинга одной и той же сущности делать вызов метода Entity:
modelBuilder.Entity<Product>() .ToTable("Products"); modelBuilder.Entity<Product>() .HasKey(p => p.Id); modelBuilder.Entity<Product>() .Property(p => p.Name) .HasColumnName("Name") .HasMaxLength(100) .IsRequired(); // и так далее...
Второй способ
Второй способ, скорее всего, особенно понравится тем, кто работал с NHibernate. Дело в том, что в этом случае настройка каждой сущности производится в отдельном классе. Для этого достаточно унаследовать класс с настройками типа от EntityTypeConfiguration
public class ProductTypeConfiguration : EntityTypeConfiguration<Product> { public ProductTypeConfiguration() { ToTable("Products"); HasKey(p => p.Id); Property(p => p.Name) .HasColumnName("Name") .HasMaxLength(100) .IsRequired(); } } public class CategoryTypeConfiguration : EntityTypeConfiguration<Category> { public CategoryTypeConfiguration() { ToTable("Categories"); Property(c => c.Name) .HasColumnName("CategoryName"); } }
А затем в том же методе OnModelCreating укажем конфигурацию маппинга:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { // настройка параметров таблицы через Fluent API modelBuilder.Configurations .Add(new ProductTypeConfiguration()) .Add(new CategoryTypeConfiguration()); }
Теперь чтобы изменить какие-либо параметры нет необходимости искать среди множества строк нужную. Достаточно лишь перейти к соответствующему классу конфигурации и произвести необходимые настройки.
Итак, мы рассмотрели два способа настройки маппинга Entity Framework через fluent-интерфейс. Какой из них использовать - дело каждого. В первом способе не нужно писать дополнительные классы конфигурации. Второй способ кажется более прозрачным и понятным, а также аналогичен подходу в NHibernate.
Комментариев нет:
Отправить комментарий