Есть ли способ динамически добавить DbSet в ядро ​​EF и использовать Linq для динамического DbSet?

Я использую EF Core v. 5.0 и базу данных SQLite и пытаюсь динамически добавить DbSet в свой DbContext. Я следовал этому руководству и повторно адаптировал его для EF Core: https://romiller.com/2012/03/26/dynamically-building-a-model-with-code-first/ и я реализовал этот класс DbContext:

     internal class GenericAppContext : DbContext
    {
        public GenericAppContext()
        {
            //Disable the EF cache system to execute every running the OnModelCreating method. 
            //ATTENTION: This is a performance loss action!
            this.ChangeTracker.LazyLoadingEnabled = false;
        }

        protected override void OnConfiguring(DbContextOptionsBuilder options)
        {
            var baseDir = AppDomain.CurrentDomain.BaseDirectory;

            //if "bin" is present, remove all the exceeding path starting from "bin" word
            if (baseDir.Contains("bin"))
            {
                int index = baseDir.IndexOf("bin");
                baseDir = baseDir.Substring(0, index);
            }

            options.UseSqlite($"Data Source = {baseDir}Database\\TestSQLite.db");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            MethodInfo addMethod = typeof(ModelBuilder).GetMethods().First(e => e.Name == "Entity");

            foreach (var assembly in AppDomain.CurrentDomain
              .GetAssemblies()
              .Where(a => a.GetName().Name != "EntityFramework"))
            {
                IEnumerable<Type> configTypes = assembly
                  .GetTypes()
                  .Where(t => t.BaseType != null
                    && t.BaseType.IsGenericType
                    && t.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));

                foreach (var type in configTypes)
                {
                    Type entityType = type.BaseType.GetGenericArguments().Single();

                    object entityConfig = assembly.CreateInstance(type.FullName);
                    addMethod?.MakeGenericMethod(entityType)
                      .Invoke(modelBuilder, new object[] { });
                }
            }
        }
    }

Мои классы "Блог" и "Статья":

    internal class Blog : EntityTypeConfiguration<Blog>
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Category { get; set; }
    }

    internal class Article : EntityTypeConfiguration<Article>
    {        
        [Key]
        public int Id { get; set; }
        public string Body { get; set; }
    }

И вот как я инициализировал DbContext, в переменной "tables" я вижу, что таблица "Article" добавляется динамически с использованием context.Model.GetRelationalModel().Tables.ToList()

        public static string TestMethod()
        {  
            using (var context = new GenericAppContext())
            {
                string result = string.Empty;

                //Ensures that the database for the context exists. If it exists, no action is taken. If it does not exist then the database and all its schema are created.
                context.Database.EnsureCreated();

                List<ITable> tables = context.Model.GetRelationalModel().Tables.ToList(); 
            }
        }

На данный момент я успешно увидел динамически добавленный класс «Статья», но я, конечно, не могу запросить «Статью» с помощью Linq, потому что он физически не существует в DbContext.

Есть ли способ использовать Linq против динамической добавленной таблицы DbSet, такой как «Статья»?

Если DbSet не существует, вы можете использовать context.Set<Entity>() для запроса

Yinqiu 22.12.2020 04:21

@Yinqiu спасибо за ответ. Проблема в том, что context.Set<Entity>() требует, чтобы класс "Article" передавался напрямую, вы не можете передать его динамически, как хотелось бы, например: object instantiatedObject = Activator.CreateInstance(objectType); context.Set<instantiatedObject>();

MarGraz 22.12.2020 18:57
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
1 450
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В конце концов я решил использовать «Linq.Dynamic.Core», который позволяет вам использовать Linq и писать лямбда-выражение в виде строки, и многое другое, здесь больше информации о Dynamic Linq.

Вот как я изменил TestMethod(), показанный ранее, и как я выполнил запрос к таблице «Статья», добавленной динамически через мой класс «GenericContextApp».

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
    
    public static string TestMethod()
        {  
            using (var context = new GenericAppContext())
            {
                string result = string.Empty;

                //Ensures that the database for the context exists. If it exists, no action is taken. If it does not exist then the database and all its schema are created.
                context.Database.EnsureCreated();

                IEnumerable<IEntityType> contextEntitiesList = context.Model.GetEntityTypes();
                IQueryable<IEntityType> entitiesList = contextEntitiesList.Select(p => p).ToList().AsQueryable();

                //Query against the dinamycally added "Article" table. It will return the SQL query as a string.
                result = context.Query("Your.Complete.Namespace.Article").Where("Body == \"ciao\"").ToQueryString();   

                return result;
            }
        }

Другие вопросы по теме