在Code First Entity Framework中指定除dbo之外的SQL用户名(C#ASP.NET MVC 3)
我正在尝试从通过EF(代码优先)连接的ASP.NET MVC 3应用程序中的C#连接到共享托管环境中的SQL Server 2008数据库。
我的问题是生成的SELECT
语句如下所示:
SELECT ... FROM [dbo].[TableName]
抛出错误Invalid object name
,但在我这样做时工作正常:
SELECT ... FROM [mySQLUserName].[TableName]
如何指定dbo
以外的用户名(例如mySQLUserName
)?
编辑:
我发现的与此问题相关的最接近的文章是:
- http://weblogs.asp.net/scottgu/archive/2010/08/03/using-ef-code-first-with-an-existing-database.aspx
- http://weblogs.asp.net/scottgu/archive/2010/07/23/entity-framework-4-code-first-custom-database-schema-mapping.aspx
特别强调第二篇文章,但它没有指定如何设置除dbo
之外的用户名
您可以使用TableAttribute
用于装饰实体类的属性来指定架构。
[Table("TableName", Schema = "mySQLUserName")]
您没有说出您正在使用的EF版本。 如果您正在使用Code First(4.1),则可以在表属性上指定架构:
[Table("Users", Schema = "myschema")] public class User { .. }
您可以使用Scott的文章(第二篇)作为基础,但您添加了一个额外的参数。 即:
modelBuilder.Entity().ToTable("TableName", "SchemaName");
使用EF6,您现在可以执行此操作。
protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.HasDefaultSchema("logs"); //set default schema modelBuilder.Configurations.Add(new LogMap()); ... }
我知道这个问题有点老了,但是我在研究中遇到了这个问题并提出了一个可能使其他人受益的解决方案,并且已经与@ppumkin进行了私下讨论。
模式名称可以作为字符串传递给ToTable()方法,因此基本上使用包含类的成员而不是硬编码值允许您在创建上下文时动态指定模式名称。
这是我所拥有的一个愚蠢的版本:
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; } }
和映射抽象类:
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); } }
执行:
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); } }
这里要注意的关键是SchemaNameEntityConfiguration
的ToTable()
方法。 它会覆盖超类的方法,因此当实现调用ToTable(tableName)
它ToTable(tableName)
提供模式名称。
*重要说明: EntityTypeConfiguration.ToTable()
是非虚拟的,抽象SchemaNameEntityTypeConfiguration
隐藏该方法,因此如果_Map
对象的类型为EntityTypeConfiguration
则不会虚拟调用。
这是我的一个问题,但是有一个简单的(并且只是有点烦人)解决:不是实现自动提供它的基类,只需确保在_Map
类中将schemaName
传递给ToTable()
。
用法:
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)); } }
免责声明:我没有在同一程序中使用多个上下文进行测试。 它应该没有问题,但如果DbContext将模型缓存在静态类级别(而不是在实例级别),则可能是一个问题。 这可以通过创建上下文的单独子类来解决,每个子类指定不同的模式名称。
您可以使用TableAttribute装饰您的类并指定Schema,或者您可以尝试本文描述的内容。