none
Change schemaName for EF 4.1 DbContext

    Question

  • Hi,

    Is there a way to change the default schemaName ('dbo') on a centralized location. I know it can be done on DataAnnotation by including the schema name on Table attribute like this Table["{schemaName}.{tableName}"] but I don't want the schemaName to be part of my POCO classes. I also don't want to use the ToTable of the FluentAPI repeatedly on each Entities.

    Before, I was able to this by implementing custom IConfigurationConventiont from EF CPT5 but this feature was drop on 4.1. Is there any alternative solution with the RC release.

    Thanks.

    Thursday, March 24, 2011 12:16 AM

Answers

  • Found my solution using reflection. It will only execute once on the application domain so performance will not be an issue for using the reflection.

     

     public abstract class DataContext : DbContext
      {
        public string DefaultSchema { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
          if (!String.IsNullOrEmpty(DefaultSchema))
          {
            var entityMethod = modelBuilder.GetType().GetMethod("Entity");
            foreach (PropertyInfo dbSet in GetType().GetProperties().Where(t => t.PropertyType.IsGenericType && t.PropertyType.GetGenericTypeDefinition().Equals(typeof(DbSet<>))))
            {
              var entityType = dbSet.PropertyType.GetGenericArguments();
              var entityMethodGeneric = entityMethod.MakeGenericMethod(entityType);
              var entityConfig = entityMethodGeneric.Invoke(modelBuilder, null);
              var toTableMethod = entityConfig.GetType().GetMethod("ToTable", new Type[] { typeof(string), typeof(string) });
              var tableName = GetTableName(entityType.FirstOrDefault());
              toTableMethod.Invoke(entityConfig, new object[] { tableName, DefaultSchema });
            }
         
          }
          base.OnModelCreating(modelBuilder);
        }
          
    
        private string GetTableName(Type type)
        {
          var tableAttribute = type.GetCustomAttributes(false).OfType<System.ComponentModel.DataAnnotations.TableAttribute>().FirstOrDefault();
          return tableAttribute == null ? type.Name : tableAttribute.Name;
        }
    
        #endregion
      }
    

    Usage:

     

     public class SampleContext : DataContext
     {
        public DbSet<StudentEntity> Students { get; set; }
        public DbSet<ClassEntity> Classes { get; set; }
    
        public SampleContext ()
        {
          DefaultSchema = "your_namespace";
        }
     }
    

     

     

    Thursday, March 24, 2011 8:32 PM

All replies

  • Found my solution using reflection. It will only execute once on the application domain so performance will not be an issue for using the reflection.

     

     public abstract class DataContext : DbContext
      {
        public string DefaultSchema { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
          if (!String.IsNullOrEmpty(DefaultSchema))
          {
            var entityMethod = modelBuilder.GetType().GetMethod("Entity");
            foreach (PropertyInfo dbSet in GetType().GetProperties().Where(t => t.PropertyType.IsGenericType && t.PropertyType.GetGenericTypeDefinition().Equals(typeof(DbSet<>))))
            {
              var entityType = dbSet.PropertyType.GetGenericArguments();
              var entityMethodGeneric = entityMethod.MakeGenericMethod(entityType);
              var entityConfig = entityMethodGeneric.Invoke(modelBuilder, null);
              var toTableMethod = entityConfig.GetType().GetMethod("ToTable", new Type[] { typeof(string), typeof(string) });
              var tableName = GetTableName(entityType.FirstOrDefault());
              toTableMethod.Invoke(entityConfig, new object[] { tableName, DefaultSchema });
            }
         
          }
          base.OnModelCreating(modelBuilder);
        }
          
    
        private string GetTableName(Type type)
        {
          var tableAttribute = type.GetCustomAttributes(false).OfType<System.ComponentModel.DataAnnotations.TableAttribute>().FirstOrDefault();
          return tableAttribute == null ? type.Name : tableAttribute.Name;
        }
    
        #endregion
      }
    

    Usage:

     

     public class SampleContext : DataContext
     {
        public DbSet<StudentEntity> Students { get; set; }
        public DbSet<ClassEntity> Classes { get; set; }
    
        public SampleContext ()
        {
          DefaultSchema = "your_namespace";
        }
     }
    

     

     

    Thursday, March 24, 2011 8:32 PM
  • Hi Francis,

    Thanks for sharing your experience here.

    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, March 25, 2011 1:34 AM
  • Hello thanks for sharing your solution, it was really helpful.

    I'm using it but now I'm facing another issue, what's happening is that the names of the tables don't get pluralized when using this DataContext base class (I've checked and the convention "PluralizingTableNameConvention" isn't removed).

    Did you experience this behavior? Any ideas on how to solve it?

    Thanks in advance,

    Gustavo

    Tuesday, May 03, 2011 6:18 PM
  • I update the code, try this:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
          if (String.IsNullOrEmpty(DefaultSchema))
            DefaultSchema = DetechOracleDefaultSchema();
    
          if (!String.IsNullOrEmpty(DefaultSchema))
          {
            var entityMethod = modelBuilder.GetType().GetMethod("Entity");
            foreach (PropertyInfo dbSet in GetType().GetProperties().Where(t => t.PropertyType.IsGenericType && t.PropertyType.GetGenericTypeDefinition().Equals(typeof(DbSet<>))))
            {
              var entityType = dbSet.PropertyType.GetGenericArguments();
              var entityMethodGeneric = entityMethod.MakeGenericMethod(entityType);
              var entityGeneric = entityMethodGeneric.Invoke(modelBuilder, null);
              var tableName = GetTableName(entityGeneric);
              if (String.IsNullOrEmpty(tableName)) continue;
              entityGeneric.GetType().InvokeMember("ToTable", BindingFlags.InvokeMethod, null, entityGeneric, new object[] { tableName, DefaultSchema });
            }
          }
          base.OnModelCreating(modelBuilder);
        }
    
    
     internal string GetTableName(object entityGeneric)
        {
          var tableName = String.Empty;
    
          //-- Try looking on Fluent API declaration
          var entityConfig = entityGeneric.GetType().InvokeMember("_entityTypeConfiguration", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance, null, entityGeneric, new object[] { });
          var databaseName = entityConfig.GetType().InvokeMember("GetTableName", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, entityConfig, new object[] { });
          if (databaseName != null)
            tableName = (string)databaseName.GetType().InvokeMember("ToString", BindingFlags.InvokeMethod, null, databaseName, new Object[] { });
    
          if (!String.IsNullOrEmpty(tableName)) return tableName;
    
          //-- Try looking on DataAnnotation
          var entity = entityGeneric.GetType().GetGenericArguments().FirstOrDefault();
          if (entity != null)
          {
            var tableAttribute = entity.GetCustomAttributes(false).OfType<System.ComponentModel.DataAnnotations.TableAttribute>().FirstOrDefault();
            tableName = tableAttribute == null ? String.Empty : tableAttribute.Name;
          }
    
          //-- Use the EF convention if not found
          if (String.IsNullOrEmpty(tableName))
            tableName = (string)entityConfig.GetType().InvokeMember("_entitySetName", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance, null, entityConfig, new object[] { });
    
          return tableName;
        }
    

     

    Tuesday, May 10, 2011 4:35 AM
  • Is this some kind of joke?

    Couldn't this simple problem be solved with even more code?

     

    I believe it's time for the .NET crowd to stop reinventing the wheel in everything they do and take a look at the simpler common sense frameworks that "just work".

    Rails comes to mind...


    Tuesday, August 02, 2011 3:05 PM
  • Are you modifying the generated DbContext? If not, how are you inserting into these changes into the T4 flow? Thanks, Dave
    Tuesday, September 13, 2011 10:41 PM
  • Doesn't help those of us who got sucked into Model First because when EF started Code First was really ppor, and ever since, MSFT ahs forgot about Model/Database First users.

    Dave

    Monday, July 07, 2014 6:54 PM