Specify an SQL username other than dbo in Code First Entity Framework ( C# ASP.NET MVC 3 )

前端 未结 5 1712
梦毁少年i
梦毁少年i 2020-12-31 06:41

I\'m trying to connect to an SQL Server 2008 database in a shared hosting environment from C# from within an ASP.NET MVC 3 application connecting via EF (code first).

<
5条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2020-12-31 06:59

    I know this question is a bit old, but I came across it in my research and came up with a solution that may benefit others, and have discussed it privately with @ppumkin.

    The schema name can be passed as a string to the ToTable() method, so essentially using a member of the containing class instead of a hard-coded value allows you to dynamically specify the schema name upon context creation.

    This is a dumbed down version of what I have:

    public class FooDbContext : DbContext
    {
        public string SchemaName { get; set; }
    
        static FooDbContext()
        {
            Database.SetInitializer(null);
        }
    
        public FooDbContext(string schemaName)
            : base("name=connString1")
        {
            this.SchemaName = schemaName;
        }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new City_Map(this.SchemaName));
            modelBuilder.Configurations.Add(new Customer_Map(this.SchemaName));
            modelBuilder.Configurations.Add(new CustomerSecurity_Map(this.SchemaName));
            base.OnModelCreating(modelBuilder);
        }
    
        public DbSet Customers { get; set; }
        public DbSet Cities { get; set; }
    
    }
    

    And the mapping abstract class:

    public abstract class SchemaNameEntityTypeConfiguration : EntityTypeConfiguration where TEntityType : class
    {
        public string SchemaName { get; set; }
        public SchemaNameEntityTypeConfiguration(string schemaName)
            : base()
        {
            this.SchemaName = schemaName;
        }
    
        public new void ToTable(string tableName)
        {
            base.ToTable(tableName, SchemaName);
        }
    }
    

    Implementation:

    public class City_Map : SchemaNameEntityTypeConfiguration
    {
        public City_Map(string schemaName)
            : base(schemaName)
        {
            ToTable("City");
            HasKey(t => t.Code);
    
            Property(t => t.Code)
                .HasColumnType("integer")
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
    
            Property(t => t.CityName)
                .HasColumnName("City")
                .HasMaxLength(50);
    
            Property(t => t.State)
                .HasMaxLength(2);
        }
    }
    

    The key thing to note here is the ToTable() method in SchemaNameEntityConfiguration. It overrides the superclass' method so when the implementations call ToTable(tableName) it supplies the schema name as well.

    *Important note: EntityTypeConfiguration.ToTable() is non-virtual, and the abstract SchemaNameEntityTypeConfiguration hides that method with its own and thus won't be called virtually if the _Map object is type as EntityTypeConfiguration.

    It was one concern of mine but there's an easy (and only slightly annoying) work around: instead of implementing a base class that supplies it automatically, just ensure in the _Map classes you pass the schemaName to ToTable().

    Usage:

    using (FooDbContext context = new FooDbContext("theSchemaName"))
    {
        foreach (
            var customer in context.Customers
                    .Include(c => c.City)
                .Where(c => c.CustomerName.StartsWith("AA"))
                .OrderBy(c => c.CustomerCode)
            )
        {
            Console.WriteLine(string.Format(
                "{0:20}: {1} - {2}, {3}",
                customer.CustomerCode,
                customer.CustomerName,
                customer.City.CityName,
                customer.City.State));
        }
    }
    

    Disclaimer: I haven't tested using multiple contexes within the same program. It shouldn't have an issue, but if the DbContext caches the model at a static class level (rather than at the instance-level), it could be a problem. That may be resolved by creating separate subclasses of the context though, each specifying a different schema name.

提交回复
热议问题