在代码优先实体框架(c# ASP)中指定一个SQL用户名,而不是dbo.Net MVC 3)

本文关键字:用户 SQL Net dbo 一个 MVC 实体 框架 代码 ASP | 更新日期: 2023-09-27 18:06:31

我试图连接到一个SQL Server 2008数据库在共享主机环境从c#从ASP内。. NET MVC 3应用程序通过EF连接(代码优先)。

我的问题是生成的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以外的用户名

在代码优先实体框架(c# ASP)中指定一个SQL用户名,而不是dbo.Net MVC 3)

您可以使用TableAttribute上的属性来指定模式,该属性用于装饰您的实体类。

[Table("TableName", Schema = "mySQLUserName")]

你没有说你使用的是哪个版本的EF。如果您使用Code First(4.1),您可以在表属性上指定模式:

[Table("Users", Schema = "myschema")]
public class User { .. }

您可以使用Scott的文章(第二篇)作为基础,但是您要添加一个额外的参数。即:

modelBuilder.Entity<YourType>().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<FooDbContext>(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<Customer> Customers { get; set; }
    public DbSet<City> Cities { get; set; }
}

和映射抽象类:

public abstract class SchemaNameEntityTypeConfiguration<TEntityType> : EntityTypeConfiguration<TEntityType> 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<City>
{
    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)时,它也提供模式名称。

*重要提示:EntityTypeConfiguration.ToTable()是非虚方法,抽象的SchemaNameEntityTypeConfiguration用自己的方法隐藏了该方法,因此如果_Map对象的类型为EntityTypeConfiguration,则不会虚调用该方法。

这是我的一个问题,但有一个简单的(只是有点烦人)的工作:而不是实现一个基类,自动提供它,只是确保在_Map类你传递schemaNameToTable()

用法:

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,或者你可以尝试这篇文章所描述的