ef core new dbcontext выполняет OnModelCreating только один раз

у нас регулярно меняются данные базы данных (каждые две недели до одного раза в месяц). Обычно приходится использовать самые последние данные, но в некоторых особых случаях необходимы более старые данные.

Текущая информация о том, какая версия должна использоваться, хранится в другой таблице.

База данных выглядит так: версионные имена схем с теми же таблицами под ней.

YYYYMMDD+Revision

myshema_202001011
    table1
myshema_202002011 and so on
    table1
myshema_202003011 and so on
    table1

Я создал службу ядра Aspnet (2.2) с двумя классами DbContext, один для статических схем, который использует текущую версию, и один для меняющихся схем, которые обращаются к этим данным.

Статический DbContext работает нормально.

Проблема в том, что даже когда я использую изменяющийся контакт с использованием лайка,

using (var _context = new ChangingDbContext()){}

конструкторы и OnConfiguring выполняются каждый раз, но метод OnModelCreating выполняется только один раз. Это приводит к НЕ обновлению текущих схем.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    modelBuilder.HasAnnotation("ProductVersion", "2.2.6-servicing-10079");

    modelBuilder.Entity<my_table>(entity =>
    {
        entity.HasKey(e => e.key_adr);
        entity.ToTable("mytable", $"myshema{mySchemaVersion}");
    }); 
}

Кто-нибудь знает, как получить «действительно» новый контекст, в котором OnModelCreating выполняется каждый раз? Или, может быть, другое решение, как справиться с этими меняющимися схемами?


person Mr.Pearce    schedule 06.03.2020    source источник
comment
Просто для подтверждения. Вы говорите, что ваша БД меняется каждые 2 недели. И вам нужно менять код DBContext каждые 2 недели?   -  person Alex - Tin Le    schedule 06.03.2020
comment
Да типа. Это проще, чем взорвать исходные таблицы, которые мы получаем с некоторой логикой пересмотра.   -  person Mr.Pearce    schedule 06.03.2020
comment
Ну, это первый раз, когда я слышу это. Я думаю, вы можете сделать динамические столбцы для таблиц. Я объясню больше в ответе.   -  person Alex - Tin Le    schedule 06.03.2020


Ответы (2)


В продолжение моего комментария. Приведенный ниже дизайн таблицы базы данных позволяет вам или пользователям добавлять столько новых полей к объекту, сколько они хотят. И я думаю, что это дает наиболее гибкую структуру.

Предположим, в системе электронной коммерции мы предоставляем 3 поля (название, код, цена) для продукта. Но мы также позволяем пользователям добавлять свои настраиваемые поля к своим продуктам (например, Promotion1Price, Promotion2Price, Discount, ...)

ПРОДУКТ (ProductId, Название, Код, Цена)

CUSTOMEFIELD (FieldId, FieldName, FieldType)

PRODUCT_CUSTOMFIELD (ProductId, FieldId, FieldValue)

Дайте мне знать, если это не соответствует вашей цели.

person Alex - Tin Le    schedule 06.03.2020
comment
Столы сами по себе не являются проблемой. Изменения в таблице (новые столбцы и прочее) известны за месяц, поэтому с ними можно легко справиться задолго до того, как они станут актуальными. Единственное, что меня блокирует, это то, что OnModelCreating запускается только один раз, и поэтому схема таблицы для моего контекста не изменится. У меня есть метод, который настраивает имена схем для DbContext, но когда OnModelCreating запускается только после того, как он не будет обновляться. - person Mr.Pearce; 06.03.2020
comment
То, что я пытаюсь сказать, это. Ваша основная проблема заключается в том, что таблица должна часто меняться. Тогда правильное решение — спроектировать таблицы, которые позволяют часто меняться. Ваше решение состоит в том, чтобы разработать код, который будет часто меняться. И я не думаю, что это хороший дизайн. Потому что я не вижу смысла превращать проблему изменения таблицы в изменение кода. Надеюсь, это имеет смысл. - person Alex - Tin Le; 06.03.2020

Решено этим ответом https://stackoverflow.com/a/41985226/6692289

Цитата из примера на случай, если он будет удален.

Derived DbContext that replaces it's ModelCacheKey (and factory) with a Custom one.

class MyDbContext : DbContext
{
    public MyDbContext(string schema)
    {
        Schema = schema;
    }

    public string Schema { get; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options
            .UseSqlServer("...")
            .ReplaceService<IModelCacheKeyFactory, MyModelCacheKeyFactory>();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasDefaultSchema(Schema);

        // ...
    }
}

Фабрика, которая создает контекст с определенным ключом.

class MyModelCacheKeyFactory : IModelCacheKeyFactory
{
    public object Create(DbContext context)
        => new MyModelCacheKey(context);
}

Пользовательский ModelCacheKey для каждого контекста.

class MyModelCacheKey : ModelCacheKey
{
    string _schema;

    public MyModelCacheKey(DbContext context)
        : base(context)
    {
        _schema = (context as MyDbContext)?.Schema;
    }

    protected override bool Equals(ModelCacheKey other)
        => base.Equals(other)
            && (other as MyModelCacheKey)?._schema == _schema;

    public override int GetHashCode()
    {
        var hashCode = base.GetHashCode() * 397;
        if (_schema != null)
        {
            hashCode ^= _schema.GetHashCode();
        }

        return hashCode;
    }
}

И с помощью контекста, как.

using (var _myContext = new MyDbContext(_schemaNameToUse)
{
}
person Mr.Pearce    schedule 06.03.2020