Как известно, в 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.
Комментариев нет:
Отправить комментарий