Pages

Friday, June 24, 2011

Custom Table Mapping with Entity Framework (EF) 4.1

I used EF 4.1 Code-First feature to develop a quick prototype for a QA team recently. Now more functionality is being added to the web application (ASP.NET MVC 3) and I need to display data from log4net's Log table. For that purpose I have to hook up another database, create a model with repository, and a new Data Context. Here I will list a few findings regarding conventions. They really become convenient only when known and also when a workaround is available for non-standard situations.

To add another database to the project, I simply copied an existing Data Context class and changed it's name. The class looked like this:

 

    public class MySecondSystem : DbContext
    {

        public MySecondSystem()
        {
        }

        public DbSet<ESBStubMVC.Models.Log> Logs { getset; }

    }

 

The original context's name had "Context" suffix but I removed that. The convention for finding a connection string is that a Connection String with the same Name will be loaded from Web.Config. Since there was already a Connection String with name "MySecondSystem" used for other purposes, adjusting the class name was the quickest way to make it use the same connection string. However, adding providerName to the connectionString tag is required for Code-First to work:

 

providerName="System.Data.SqlClient"

 

Class Log represents existing log4net Log table:

 

    public class Log
    {
        public int Id { getset; }

        public DateTime Date { getset; }
        
        [StringLength(255, ErrorMessage = "The {0} must be at least {2} characters long.")]
        public string Thread { getset; }
        
        [StringLength(50, ErrorMessage = "The {0} must be at least {2} characters long.")]
        public string Level { getset; }
        
        [StringLength(255, ErrorMessage = "The {0} must be at least {2} characters long.")]
        public string Logger { getset; }
        
        [StringLength(4000, ErrorMessage = "The {0} must be at least {2} characters long.")]
        public string Message { getset; }
        
        [StringLength(2000, ErrorMessage = "The {0} must be at least {2} characters long.")]
        public string Exception { getset; }

    }

 

In the LogRepository, created by MvcScaffolding, I just changed the data context class since it had picked up an old, existing one:

 

    public class LogRepository : ILogModelRepository
    {
        MySecondSystem context = new MySecondSystem();

 

Now, to actually read from Log table, as opposed to Logs - plural is used by convention - I had to add a custom mapping. This is easy enough to set by overriding OnModelCreating:

 

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            // Custom mapping.
            modelBuilder.Entity<Log>().Map(c => c.ToTable("Log"));
        }

 

So, the final Data Context class looks like this:

 

    public class MySecondSystem : DbContext
    {

        public MySecondSystem()
        {
        }

        public DbSet<ESBStubMVC.Models.Log> Logs { getset; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            // Custom mapping.
            modelBuilder.Entity<Log>().Map(c => c.ToTable("Log"));
        }
    }

 

 

No comments: