我可以为任何 Table/Entity 传递参数使用通用方法吗?
Can I have generic method for any Table/Entity passed a parameter?
我有一个控制器 class 并且有一个方法以 tableName 作为参数。
最多可以有 30 个开关盒 tables/cases.
控制器
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;
}
}
界面
public interface IExtractService
{
public Task<List<TEntity>> GetDataAsync<TEntity>( string pRtUnique) where TEntity : BaseEntity;
}
实施:
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();
}
}
我可以根据 table 从控制器 class 获得通用的 code/call 吗?不喜欢简单地使用 30 个条件的 switch 语句来从 table 检索数据。您好,希望您了解我目前面临的挑战。我可以有一个方法调用应该适用于所有 tables 吗?
这里有一个视图选项来实现你想要的。
- 您可以使用 EF 和 DbContext.Set 方法
- 您可以为您的 table 创建存储 procedures/query 以及那是什么
方法需要调用。
- 最后您可以创建 SQL 表达式并插入 table 名称
第一个看起来像这样:
DbContext.Set(System.Type.GetType("tableName"))
第二种可能是这样
var db = new DbContext();
var list = db.ExecuteStoreQuery<Obj>(Obj.sql);
class Obj
{
public const string sql = @"select [tbl].[field] from [tbl]";
}
最后,您只需发送一个 sql 查询,它就会正常工作。
var query =$"select * from {table} where <some_condition>";
var list = db.ExecuteStoreQuery<Obj>(query);
这些都可以工作并实现您的目标,即能够将 tableName 传递到方法中并取回通用对象类型结果。我确信还有其他方法,但在过去我通常只是创建一个字符串并制作一个自定义 sql 查询字符串并使用 ExecuteStoreQuery<>().
发送到数据库
我在反射和MakeGenericMethod的帮助下解决了。详情请参考 link
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;
}
}
我有一个控制器 class 并且有一个方法以 tableName 作为参数。 最多可以有 30 个开关盒 tables/cases.
控制器
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;
}
}
界面
public interface IExtractService
{
public Task<List<TEntity>> GetDataAsync<TEntity>( string pRtUnique) where TEntity : BaseEntity;
}
实施:
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();
}
}
我可以根据 table 从控制器 class 获得通用的 code/call 吗?不喜欢简单地使用 30 个条件的 switch 语句来从 table 检索数据。您好,希望您了解我目前面临的挑战。我可以有一个方法调用应该适用于所有 tables 吗?
这里有一个视图选项来实现你想要的。
- 您可以使用 EF 和 DbContext.Set 方法
- 您可以为您的 table 创建存储 procedures/query 以及那是什么 方法需要调用。
- 最后您可以创建 SQL 表达式并插入 table 名称
第一个看起来像这样:
DbContext.Set(System.Type.GetType("tableName"))
第二种可能是这样
var db = new DbContext();
var list = db.ExecuteStoreQuery<Obj>(Obj.sql);
class Obj
{
public const string sql = @"select [tbl].[field] from [tbl]";
}
最后,您只需发送一个 sql 查询,它就会正常工作。
var query =$"select * from {table} where <some_condition>";
var list = db.ExecuteStoreQuery<Obj>(query);
这些都可以工作并实现您的目标,即能够将 tableName 传递到方法中并取回通用对象类型结果。我确信还有其他方法,但在过去我通常只是创建一个字符串并制作一个自定义 sql 查询字符串并使用 ExecuteStoreQuery<>().
发送到数据库我在反射和MakeGenericMethod的帮助下解决了。详情请参考 link 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;
}
}