You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:35:31