I have a controller class and has one method which has tableName as parameter. and can have switch cases for up to 30 tables/cases.
Controller
public async Task<IActionResult> GetData(string tableName, string pRtUnique)
{
var tableEnum = Enum.Parse<AssetInitial>(tableName);
switch (tableEnum )
{
case AssetInitial.Table1:
return Ok(ApiResult<List<Table1>>.Success200(await _extractService.GetDataAsync<Table1>(pRtUnique)));
break;
case AssetInitial.Table2: ..... break;
case AssetInitial.Table3: ..... break;
case AssetInitial.Table30: ..... break;
}
}
Interface
public interface IExtractService
{
public Task<List<TEntity>> GetDataAsync<TEntity>( string pRtUnique) where TEntity : BaseEntity;
}
Implementation:
public class ExtractService : IExtractService
{
private readonly DbContext _context;
public ExtractService(DbContext context)
{
_context = context;
}
public async Task<List<TEntity>> GetDataAsync<TEntity>(string pRtUnique) where TEntity : BaseEntity
{
return await _context.Set<TEntity>().Where(x => x.RtUnique== pRtUnique).ToListAsync();
}
}
Can I have generic one code/call from controller class based on table. Don't like simply have a switch statement for 30 conditions to just retrieve data from table. HI hope you have understood the challenge currently I am going with. Can I have one method call which should work for all tables ?
CodePudding user response:
You have a view options here to achieve what you are wanting.
- You can use EF and the DbContext.Set method
- You can created stored procedures/query for your table and what that method needs to call.
- Last you can create SQL expressions and insert the table name
The first looks like this:
DbContext.Set(System.Type.GetType("tableName"))
The second could be like this
var db = new DbContext();
var list = db.ExecuteStoreQuery<Obj>(Obj.sql);
class Obj
{
public const string sql = @"select [tbl].[field] from [tbl]";
}
And last you could just make a sql query to send over and it will work just the same.
var query =$"select * from {table} where <some_condition>";
var list = db.ExecuteStoreQuery<Obj>(query);
These all can work and achieve your goal of being able to pass a tableName into a method and get back generic object type results. I am sure there are other ways, but in the past I normally just create a string and make a custom sql query string and send to database using the ExecuteStoreQuery<>().
CodePudding user response:
I solved with the help of reflection and MakeGenericMethod. Please refer the link for more details https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodinfo.makegenericmethod?view=net-6.0
public class EnityRepository<TEntity> : IEnityRepository<TEntity> where TEntity : BaseEntity
{
private readonly DContext _context;
public EnityRepository(DContext context)
{
_context = context;
}
public async Task<List<object>> GetDataAsync(string tablename, string pRtUnique)
{
List<TEntity> result = new List<TEntity>();
var type = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.Name == tablename);
var tableSet = _context.Set<TEntity>(type);
result = await tableSet.Where(x => x.RtUnique == pRtUnique).ToListAsync();
return result.Cast<object>().ToList();
}
}
//Created extension method
public static class ContextSetExtension
{
public static IQueryable<TEntity> Set<TEntity>(this HIVEiKYTCDContext _context, Type t) where TEntity : BaseEntity
{
var method = typeof(DContext).GetMethods().Single(p => p.Name == nameof(DContext.Set) && p.ContainsGenericParameters && !p.GetParameters().Any());
method = method.MakeGenericMethod(t);
var res = method.Invoke(_context, null);
return (IQueryable<TEntity>)res;
}
}