Dynamically select DbSet member from DbContext?

275 views Asked by At

I want to create a dynamic OData controller which can be inherited by concrete OData controllers. In order to do that, I need to way to select the proper DbSet from my DbContext and use it in the controller. However, I have no clue how to write this down in C#. This is what I tried:

Background is that there are two tables in the database with the exact same structure, but the requirement is to keep them apart since they contain different types of data. So I want a dynamic FileData controller where I can pass the desired type to and basically code everything once in the FileData controller.

Database context

    public class DS2DbContext : DbContext
    {
        public DbSet<DocumentFileData> DocumentFileData { get; set; }
        public DbSet<WatermarkFileData> WatermarkFileData { get; set; }
        public DS2DbContext(DbContextOptions<DS2DbContext> options) : base(options) { }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
    }

Controller

    public class FileDataController<T> : ODataController
    {
        private readonly DS2DbContext _context;

        private readonly ILogger<FileDataController<T>> _logger;

        // --------------------------------------------------

        public FileDataController(DS2DbContext dbContext, ILogger<FileDataController<T>> logger)
        {
            _logger = logger;
            _context = dbContext;
        }

        public DbSet<T> DB()
        // Error CS0452: 
        // The type 'T' must be a reference type in order to use it as parameter
        // 'TEntity' in the generic type or method 'DbSet<TEntity>'
        {
            PropertyInfo pi = _context.GetType().GetProperty(nameof(T));
            MethodInfo mi = pi.GetGetMethod();
            return (DbSet<T>)mi.Invoke(this, null); // error CS0452
        }

        [EnableQuery(PageSize = 15)]
        public IQueryable<T> Get()
        {
            //return _db.FileData;
            return DB();
        }

        [EnableQuery]
        public SingleResult<WatermarkFileData> Get([FromODataUri] Guid ID)
        {
            //var result = _db.FileData.Where(c => c.ID == ID);
            var result = DB().Where(c => c.ID == ID);
            return SingleResult.Create(result);
        }
    }
1

There are 1 answers

2
MindSwipe On BEST ANSWER

No need for a custom method to do that, use the DbContext.Set<T> method.

To fix your compile error you'll need to add a generic constraint to your controller class, like so:

public class FileDataController<T> : ODataController where T : class

Note the where T : class, this is required because the DbSet class itself has the where TEntity : class constraint