1. | As we saw in the earlier article Code First Entity Framework - Data Annotations, you can mark up your data object using attributes to control how Entity Framework generates a database to match your data objects. Some people don't like using Data Annotations, and EF provides a programmatic alternative. |
2. |
Like before we have our data object, and we'll use the same example as last time of a school, and you need a Pupil object.
You design the POCO object in code with 4 properties, id, name, DOB, and primary school attended:using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace TestEF.Entity { public class Pupil { public int PupilId { get; set; } public string Name { get; set; } public DateTime DateOfBirth { get; set; } public string PrimarySchool { get; set; } } } |
3. |
This time, instead of annotating the elements with attributes, we can programmatically do it in the code behind, and in particular
by overriding the OnModelCreating event of the DB context.
using System.Data; using System.Data.Entity; using System.Data.EntityModel; namespace TestEF.Contexts { public class SchoolContext : DbContext { public DbSet<TestEF.Entity.Pupil> Pupils { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // we will put our Fluent code here } } } |
4. |
OK, as with last time where we used the [Key] attribute, we start with assigning which member is the Primary Key.
modelBuilder.Entity<TestEF.Entity.Pupil>()
.HasKey(fp => fp.PupilId);
This tells the modelBuilder that the Pupil entity (and the database to be created) has PupilId as its primary key.
This is functionally identical to using the [Key] Data Annotation on the data object.
|
5. |
Last time we then added the [Required] annotation to the first three members that we wanted to
be non-nullable in the database. This time we do it in code:
modelBuilder.Entity<TestEF.Entity.Pupil>() .Property(fp => fp.PupilId) .IsRequired(); modelBuilder.Entity<TestEF.Entity.Pupil>() .Property(fp => fp.Name) .IsRequired(); modelBuilder.Entity<TestEF.Entity.Pupil>() .Property(fp => fp.DateOfBirth) .IsRequired();This tells the modelBuilder that the for the PupilId, Name and DateOfBirth properties of the Pupil entity, they are required, and should be non nullable in the database. |
6. |
In the same vein, we can add the annotations for StringLength and the Identity column to the elements,
giving the completed OnModelCreating section:
using System.Data; using System.Data.Entity; using System.Data.EntityModel; using System.ComponentModel.DataAnnotation; namespace TestEF.Contexts { public class SchoolContext : DbContext { public DbSet<TestEF.Entity.Pupil> Pupils { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<TestEF.Entity.Pupil>() .HasKey(fp => fp.PupilId); modelBuilder.Entity<TestEF.Entity.Pupil>() .Property(fp => fp.PupilId) .IsRequired(); .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); modelBuilder.Entity<TestEF.Entity.Pupil>() .Property(fp => fp.Name) .IsRequired() .HasMaxLength(200); modelBuilder.Entity<TestEF.Entity.Pupil>() .Property(fp => fp.DateOfBirth) .IsRequired(); modelBuilder.Entity<TestEF.Entity.Pupil>() .Property(fp => fp.PrimarySchool) .HasMaxLength(200); } } }Note to use the DatabaseGeneratedOption enum we need to add a using line for System.ComponentModel.DataAnnotation (or use the fully qualified name in the code) |
7. | Now if we make sure we've added our model context data generation line to the Golbal.asax, and make sure we consume our SchoolContext from a webpage codebehind or MVC controller (see how we did this in the last article) then we will see that EF creates our database as specified by the Fluent API. |
8. |
If you think that seems a little bloaty compared with the data Annotation version, you have to consider that
the Fluent API can do things that would be more difficult with the Annotation version, such as: Composite primary key If we wanted id and name as the combined key, we can do that
modelBuilder.Entity<TestEF.Entity.Pupil>()
.HasKey(p => new { p.PupilId, p.Name });
Ignore a propertyIf the model contains elements we don't need to persist, we can tell EF
modelBuilder.Entity<TestEF.Entity.Pupil>()
.Ignore(p => p.PrimarySchool);
Change column mappingIf we need the DB to have a different column name for the entity modelBuilder.Entity<TestEF.Entity.Pupil>() .Property(p => p.Name) .HasColumnName("PupilName");Change table mapping If we need the DB table to have a different name modelBuilder.Entity<TestEF.Entity.Pupil>() .ToTable("Pupils_2011");There are many more things you can do with the Fluent API, especially with regards to mappings between inherited classes and how they are stored in the database, but these are the basics. |
And that's the basics of Entity Framework code-first using the Fluent API. |