Как передать определенный тип DbSet в класс, чтобы он определил тип нужной таблицы

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

public class CollageUnitsDb : DbContext
    {
        private const string CONNECTION_STRING = @"...";

        public CollageUnitsDb() : base(CONNECTION_STRING)
        {

        }

        public DbSet<Group> Groups { get; set; }
        public DbSet<Teacher> Teachers { get; set; }
    }

Чтобы привести их под 1 тип(DbSet<Group> и DbSet<Teacher>) я реализовал интерфейс у обоих классов

public sealed class Group : IUnit
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

public sealed class Teacher : IUnit
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

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

public abstract class BaseUnitsContainer
    {
        private HttpClass http = HttpClass.GetInstace();
        private List<string> Titels { get; set; }

        protected BaseUnitsContainer(IParser parser, IUnit unit)
        {
            Titels = http.GetRecentDataArray(parser);

            if (Titels is null)
            {
                using (var context = new CollageUnitsDb())
                {
                    Titels = context.Select(x => x.Name).ToList();
                }
            }
            else
            {
                RefreshTable();
            }
        }

        public abstract void RefreshTable();

        protected List<string> GetTitels()
        {
            return Titels;
        }
    }

Краткая суть логики конструктора: В него передается некий класс IParser с переопределенным методом парсинга, тот в свою очередь возвращает спарсенные данные. Если данных нет, мы должны их взять с таблицы(базы данных). Вот тут и получается загвоздка. Я могу с наследуемых классов передать в базовый метод нужный мне класс, чтобы он понял какую таблицу дать. Но проблема в том, что я не знаю как объяснить ему, какая таблица мне нужна


Классы наследники

public sealed class TeachersContainer : BaseUnitsContainer
    {
        private static readonly TeachersContainer teachersContainer = new TeachersContainer();

        public List<string> TeacherTitels { get; set; }

        private TeachersContainer() : base(new ParserTeachers(), new Teacher())
        {
            TeacherTitels = GetTitels();
        }
    }

public sealed class GroupsContainer : BaseUnitsContainer
    {
        private static readonly GroupsContainer groupsContainer = new GroupsContainer();

        public List<string> GroupsTitels { get; set; }

        private GroupsContainer() : base(new ParserGroups(), new Group())
        {
            GroupsTitels = GetTitels();
        }
     }

Часть кода, которая будет везде повторятся(её я хочу перенести в базовый класс)

Titels = http.GetRecentDataArray(parser);

            if (Titels is null)
            {
                using (var context = new CollageUnitsDb())
                {
                    Titels = context.Select(x => x.Name).ToList();
                }
            }
            else
            {
                RefreshTable();
            }

Ответы (2 шт):

Автор решения: Aarnihauta

Можно использовать дженерики

Для начала сделаем интерфейс, передавать в конструктор будем не DbSet, а интерфейс, который обязаны реализовать все классы, работающие с бд.

interface IDataStore<T>
{
    //тут можно добавить и другие методы CRUD

    Task<IEnumerable<T>> GetItems();
}

Реализуем этот интерфейс:

class TeacherDataStore : IDataStore<Teacher>
{
    private CollageUnitsDb _context = new CollageUnitsDb();
    public async Task<IEnumerable<Teacher>> GetItems()
    {
        return await Task.FromResult(_context.Teachers.ToList());
    }
}

А наш абстрактный базовый класс сделаем дженериком:

abstract class BaseUnitsContainer<T> where T: IUnit
{
    private HttpClass http = HttpClass.GetInstace();
    public List<string> Titles{ get; set; }
    protected BaseUnitsContainer(IParser parser, IDataStore<T> store)
    {
        Titles= http.GetRecentDataArray(parser);
        if (Titels is null)
        {
            SetTitles(store);
        }
        else
        {
            RefreshTable();
        }
    }

    protected async void SetTitles(IDataStore<T> store)
    {
        var items = await store.GetItems();
        Titles= items.Select(x => x.Name).ToList();
    }
}

Реализуем контейнер для класса Teacher:

class TeacherUnitsContainer : BaseUnitsContainer<Teacher>
{
    public TeacherUnitsContainer(IParser parser, IDataStore<Teacher> store) 
                                : base(parser, store) { }
}
→ Ссылка
Автор решения: Nikita

Реализовал подобное следующим образом: В служебном классе по работе с Raflaction реализовал функцию получения значения по имени переменной класса:

public static Object GetByName(this Object obj, string name)
{
    BindingFlags flags = BindingFlags.Instance | BindingFlags.Public;
    PropertyInfo[] property = obj.GetType().GetProperties(flags);
    foreach (var pi in property)
    {
        if (pi.Name == name) return pi.GetValue(obj);
    }
    return null;
}

далее, при обращении к базе:

void SomeFunction<TEntity>(TEntity obj) where TEntity : class
{
    dynamic list = null;
    dynamic dbset = null;
    string typeName = obj.GetType().Name;
    
    dbset = content.GetByName(typeName + "s");
    list = (dbset as DbSet<TEntity>).Where(...).ToList();
    ...
}
→ Ссылка