.NET Core控制器动态传递泛型对象实现表格动态展示
我来帮你搞定这个动态展示表格的需求!下面是从后端转换到前端渲染的完整实现方案:
动态表格展示全流程实现
第一步:补全DataTable转泛型列表的工具方法
你已经有了一个不错的开头,我来帮你完善这个转换逻辑,它会自动把DataTable的每一行映射到对应实体类的属性上:
public static List<T> ConvertTableToList<T>(this DataTable table) where T : class, new() { try { List<T> dataList = new List<T>(); foreach (DataRow row in table.AsEnumerable()) { T entity = new T(); // 遍历实体类的所有属性 foreach (var prop in entity.GetType().GetProperties()) { // 匹配DataTable中对应的列(忽略大小写) var targetColumn = table.Columns.Cast<DataColumn>() .FirstOrDefault(col => string.Equals(col.ColumnName, prop.Name, StringComparison.OrdinalIgnoreCase)); if (targetColumn != null && row[targetColumn] != DBNull.Value) { // 处理类型转换,适配常见数据类型 var convertedValue = Convert.ChangeType(row[targetColumn], prop.PropertyType); prop.SetValue(entity, convertedValue); } } dataList.Add(entity); } return dataList; } catch (Exception ex) { // 这里可以添加日志记录,方便排查问题 throw new Exception("DataTable转实体列表失败", ex); } }
第二步:后端.NET Core控制器实现动态数据接口
接下来写一个接口,接收前端传来的表名,查询数据库获取数据后转成泛型列表返回JSON。这里一定要注意SQL注入防护,绝对不能直接把用户输入拼到SQL里:
[ApiController] [Route("api/table")] public class DynamicTableController : ControllerBase { private readonly IConfiguration _config; public DynamicTableController(IConfiguration config) { _config = config; } [HttpPost("get-data")] public IActionResult GetDynamicTableData([FromBody] TableQueryRequest request) { try { // 1. 校验表名合法性(白名单方式最安全) if (!IsValidTableName(request.TableName)) { return BadRequest("无效的表名,请选择合法选项"); } // 2. 查询数据库获取DataTable DataTable table = new DataTable(); string connStr = _config.GetConnectionString("DefaultConnection"); using (SqlConnection conn = new SqlConnection(connStr)) { string query = $"SELECT * FROM {request.TableName}"; using (SqlDataAdapter adapter = new SqlDataAdapter(query, conn)) { adapter.Fill(table); } } // 3. 根据表名匹配对应实体类,转换为泛型列表 Type entityType = GetEntityTypeByTableName(request.TableName); if (entityType == null) { return BadRequest("未找到对应表的实体定义"); } var convertMethod = typeof(YourExtensionClass).GetMethod("ConvertTableToList") .MakeGenericMethod(entityType); var resultList = convertMethod.Invoke(null, new object[] { table }); return Ok(resultList); } catch (Exception ex) { return StatusCode(500, $"数据获取失败:{ex.Message}"); } } // 白名单校验表名,防止SQL注入 private bool IsValidTableName(string tableName) { var allowedTables = new List<string> { "Customers", "Orders", "Products", "Employees" }; return allowedTables.Contains(tableName); } // 表名与实体类的映射逻辑 private Type GetEntityTypeByTableName(string tableName) { return tableName switch { "Customers" => typeof(Customer), "Orders" => typeof(Order), "Products" => typeof(Product), "Employees" => typeof(Employee), _ => null }; } } // 前端请求模型 public class TableQueryRequest { public string TableName { get; set; } } // 示例实体类(根据你的数据库表结构定义) public class Customer { public int Id { get; set; } public string FullName { get; set; } public string Email { get; set; } public DateTime CreateTime { get; set; } }
第三步:前端实现下拉选择+动态渲染表格
用原生JS就能快速实现,如果你用Vue/React也可以照搬这个逻辑:
<select id="tableSelect"> <option value="">请选择要查看的表</option> <option value="Customers">客户表</option> <option value="Orders">订单表</option> <option value="Products">产品表</option> </select> <div id="tableContainer" style="margin-top:20px;"></div> <script> document.getElementById('tableSelect').addEventListener('change', async function() { const selectedTable = this.value; const container = document.getElementById('tableContainer'); if (!selectedTable) { container.innerHTML = ''; return; } try { // 调用后端接口 const response = await fetch('/api/table/get-data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ TableName: selectedTable }) }); if (!response.ok) throw new Error('接口请求失败'); const tableData = await response.json(); // 动态生成表格 renderDynamicTable(tableData, container); } catch (err) { alert(err.message); } }); function renderDynamicTable(data, container) { if (data.length === 0) { container.innerHTML = '<p>该表暂无数据</p>'; return; } // 获取表头字段 const headers = Object.keys(data[0]); let tableHtml = `<table border="1" cellpadding="8" cellspacing="0"> <thead><tr>`; // 生成表头 headers.forEach(header => { tableHtml += `<th>${header}</th>`; }); tableHtml += `</tr></thead><tbody>`; // 生成表体行 data.forEach(row => { tableHtml += '<tr>'; headers.forEach(field => { tableHtml += `<td>${row[field] || ''}</td>`; }); tableHtml += '</tr>'; }); tableHtml += `</tbody></table>`; container.innerHTML = tableHtml; } </script>
核心注意点
- SQL注入防护:一定要用白名单校验表名,绝对不能直接信任用户输入的内容
- 实体类映射:确保数据库列名和实体类属性名对应(如果不匹配,可以在转换方法里添加自定义映射规则)
- 错误处理:前后端都要做好异常捕获,给用户清晰的提示
内容的提问来源于stack exchange,提问作者Somya Rawal
相关产品推荐
相关产品推荐

