Укажите имя пользователя SQL, отличное от dbo, в Code First Entity Framework (С# ASP.NET MVC 3)

Я пытаюсь подключиться к базе данных SQL Server 2008 в среде совместного размещения с С# из приложения ASP.NET MVC 3, подключающегося через EF (сначала код).

Моя проблема в том, что сгенерированный оператор SELECT выглядит так:

SELECT ... FROM [dbo].[TableName]

который выдает ошибку Invalid object name, но отлично работает, когда я делаю:

SELECT ... FROM [mySQLUserName].[TableName]

Как указать имя пользователя, отличное от dbo (например, mySQLUserName)?


EDIT:

Ближайшие статьи, которые я нашел, относятся к этой проблеме:

с особым упором на вторую статью, однако он не указывает, как установить имя пользователя, отличное от dbo

Ответы

Ответ 1

Вы можете указать схему, используя свойство на TableAttribute, которое украсит ваши классы сущностей.

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

Ответ 2

Вы не говорите, какую версию EF вы используете. Если вы используете Code First (4.1), вы можете указать схему для атрибута таблицы:

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

В качестве основы можно использовать статью Скотта (вторая), но вы добавляете дополнительный параметр. то есть:.

modelBuilder.Entity<YourType>().ToTable("TableName", "SchemaName"); 

Ответ 3

С EF6 вы можете сделать это.

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.HasDefaultSchema("logs");  //set default schema
        modelBuilder.Configurations.Add(new LogMap());
        ...
    }

Ответ 4

Я знаю, что этот вопрос немного устарел, но я наткнулся на него в своих исследованиях и придумал решение, которое может принести пользу другим, и обсудил его в частном порядке с @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);
    }
}

Ключевым моментом здесь является метод ToTable() в SchemaNameEntityConfiguration. Он переопределяет метод суперкласса, поэтому, когда реализация вызывает 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 кэширует модель на статическом уровне класса (а не на уровне экземпляра), это может быть проблемой. Это может быть разрешено путем создания отдельных подклассов контекста, хотя каждый из них указывает другое имя схемы.

Ответ 5

Вы можете украсить свой класс TableAttribute и указать схему, или вы можете попробовать, что это за post.