数据表中的多个子行,来自asp.net核心中sql server的数据

Posted

技术标签:

【中文标题】数据表中的多个子行,来自asp.net核心中sql server的数据【英文标题】:Multiple child rows in datatable, data from sql server in asp.net core 【发布时间】:2021-04-01 06:10:22 【问题描述】:

我是 ASP.NET Core 的新手,从事 ASP.NET Core 项目,我需要使用从 sql server 接收数据的数据表。在没有子行的情况下我没有问题,但我必须显示具有多个子行的数据表。我无法显示具有子行的数据表。 ajax 有很多例子,但我找不到任何来自 sql server 在 asp.net core 中的数据的例子。

如果我们简单谈谈数据库结构,有 2 个表:Order 和 OrderList。

Order:OrderId(PK-int),Customer(string),OrderDate(datetime)

OrderList:KimlikId(PK-int),OrderId(int),Product(string),Color(string),Qntty(int)

Order INNER JOIN OrderList ON Order.OrderId = OrderList.OrderId

我的模型类 OrderList 是这样的:

public class OrderList

    public int OrderId  get; set; 
    public int KimlikId  get; set; 
    public string Customer  get; set; 
    public string OrderDate  get; set; 
    public string Product  get; set; 
    public string Color  get; set; 
    public int Qntty  get; set; 

我的控制器类 OrderController 是这样的:

    public class OrderController : Controller


    public IEnumerable<OrderList> GetAllOrderList()
    
        string connectionString = "My Connection String of sql server";
        List<OrderList> sipList = new List<OrderList>();
        using (SqlConnection con = new SqlConnection(connectionString))
        
            SqlCommand cmd = new SqlCommand("SELECT * FROM Order INNER JOIN OrderList ON Order.OrderId = OrderList.OrderId ORDER BY OrderList.OrderId DESC;", con);

            con.Open();
            SqlDataReader dr = cmd.ExecuteReader();
            while (dr.Read())
            
                OrderList sip = new OrderList();
                sip.OrderId = Convert.ToInt32(dr["OrderId"].ToString());
                sip.Customer = dr["Customer"].ToString();
                sip.OrderDate = DateTime.Parse(dr["OrderDate"].ToString()).ToString("dd/MM/yyyy");
                sip.Product = dr["Product"].ToString();
                sip.Color = dr["Color"].ToString();
                sip.Qntty = Int32.Parse(dr["Qntty"].ToString());

                sipList.Add(sip);
            
            con.Close();
        

        return sipList;
    

    public IActionResult OrderIndex()
    
        List<OrderList> sipList = new List<OrderList>();
        sipList = GetAllOrderList().ToList();

        return View(sipList);
    

我的视图是这样的 OrderIndex.cshtml

@model IEnumerable<AlplerCRM.Models.OrderList>
@
ViewData["Title"] = "Ordesr";
Layout = "~/Views/Shared/_AnaLayout.cshtml";

    <table id="example" class="display" style="width:100%">
    <thead>
        <tr>
            <th></th>
            <th>OrderId</th>
            <th>Customer</th>
            <th>OrderDate</th>
        </tr>
    </thead>
</table>
@section Scripts 
@await Html.RenderPartialAsync("_ValidationScriptsPartial");


<script>
    function format(d) 
        return '<table id="childtable" cellpadding="5" cellspacing="0" border="0" style="padding-left: 50px; ">' +
            '<tr>' +
            '<td>Kimlik No</td>' +
            '<td>Product Detail</td>' +
            '<td>Product Color</td>' +
            '<td>Product Quantity</td>' +
            '</tr><tr>' +
            '<td>' + d.KimlikId + '</td>' +
            '<td>' + d.Product + '</td>' +
            '<td>' + d.Color + '</td>' +
            '<td>' + d.Qntty + '</td>' +
            '</tr>' +
            '</table>';
    
    $(document).ready(function () 
        var table = $("#example").dataTable(
            "columns": [
                
                    "className": 'details-control',
                    "orderable": false,
                    "data": null,
                    "defaultContent": ''
                ,
                 "data": "OrderId" ,
                 "data": "Customer" ,
                 "data": "OrderDate" ,
            ],
            "order": [[0, 'desc']]
        );
    );
    $('#example tbody').on('click', 'td.details-control', function () 
        var tr = $(this).closest('tr');
        var row = table.row(tr);

        if (row.child.isShown()) 
            // This row is already open - close it
            row.child.hide();
            tr.removeClass('shown');
        
        else 
            // Open this row
            row.child(format(row.data())).show();
            tr.addClass('shown');
        
    );

</script>

如何在没有 ajax 的情况下获取数据并像这样显示数据表:

【问题讨论】:

我不知道这会有多高效,但是您可以将子行值存储在父 trdata- 属性中并使用该 as shown here。但我建议使用 datatable ajax 进行数据加载,因为它更快、更容易,并且您可以更好地控制 datatable 功能。 你的意思是你已经得到了截图呈现的结果(使用 JQuery ajax 和 JQuery dataTable 插件,Ajax 用于从控制器加载数据),现在你不想使用 Ajax 加载数据?如果是这种情况,您可以使用 ViewData 或 ViewBag 将数据传递给查看,然后,在查看页面中使用以下代码获取值:var data = JSON.parse('@Html.Raw(ViewData["json"])'); //json string var items = JSON.parse('@Html.Raw(JsonSerializer.Serialize(ViewData["data"]))'); //object list。然后,您可以使用 jquery 数据表插件显示数据。 截图只是我目标的一个说明,成千上万的数据将来自数据库。我想我需要使用 Ajax 加载。通过ajax获取1个数据库表数据的datatable例子很多,但是我需要通过获取2个表的union数据来获取ajax数据。 【参考方案1】:

根据您的代码和描述,我建议您可以参考以下步骤来显示结果。

    创建如下视图模型,用于将数据绑定到JQuery DataTable插件。

     public class OrderListViewModel
     
         public int OrderId  get; set; 
         public string Customer  get; set; 
         public string OrderDate  get; set; 
    
         public List<OrderListDetailViewModel> OrderListDetails  get; set; 
    
     
     public class OrderListDetailViewModel
       
         public int KimlikId  get; set;   
         public string Product  get; set; 
         public string Color  get; set; 
         public int Qntty  get; set; 
     
    

    添加如下action方法,调用GetAllOrderList()方法获取所有OrderList,然后使用GroupBy运算符对结果进行分组(根据外部属性:OrderId、Customer和OrderDate)。

     public IEnumerable<OrderListViewModel> GetOrderList()
     
         return GetAllOrderList().GroupBy(c => new  c.OrderId, c.Customer )
             .Select(c => new OrderListViewModel()
             
                 OrderId = c.Key.OrderId,
                 Customer = c.Key.Customer,
                 OrderDate = c.FirstOrDefault().OrderDate,
                 OrderListDetails = c.Select(d => new OrderListDetailViewModel()  Qntty = d.Qntty, Color = d.Color, KimlikId = d.KimlikId, Product = d.Product ).ToList()
             ).ToList();
     
    

    使用如下代码调用上述动作方法并显示结果(Index.cshtml页面中的代码):

     <link href="https://cdn.datatables.net/1.10.22/css/jquery.dataTables.min.css" rel="stylesheet" /> 
    
     <style>
         td.details-control  background: url('https://datatables.net/examples/resources/details_open.png') no-repeat center center; cursor: pointer; 
         tr.shown td.details-control  background: url('https://datatables.net/examples/resources/details_close.png') no-repeat center center; 
     </style>
     <table id="example" class="display" style="width:100%">
         <thead>
             <tr>
                 <th></th>
                 <th>OrderId</th>
                 <th>Customer</th>
                 <th>OrderDate</th>
             </tr>
         </thead>
     </table>
     @section Scripts 
         @await Html.RenderPartialAsync("_ValidationScriptsPartial");
         <script src="https://code.jquery.com/jquery-3.5.1.js"></script>
         <script src="https://cdn.datatables.net/1.10.22/js/jquery.dataTables.min.js"></script>
         <script>
             function format(d) 
                 var result = '<table id="childtable" cellpadding="5" cellspacing="0" border="0" style="padding-left: 50px; width:80% ">' +
                     '<tr><td>Kimlik No</td><td>Product Detail</td><td>Product Color</td><td>Product Quantity</td></tr>';
                 //loop thouth the OderListDetails and add the child items.
                 for (var i = 0; i < d.orderListDetails.length; i++) 
                     var child = '<tr><td>' + d.orderListDetails[i].kimlikId + '</td>' +
                         '<td>' + d.orderListDetails[i].product + '</td>' +
                         '<td>' + d.orderListDetails[i].color + '</td>' +
                         '<td>' + d.orderListDetails[i].qntty + '</td></tr>';
                     result += child;
                 
                 result += '</table>';
                 return result;
             
             $(document).ready(function ()  
                 //call the action method and get the data.
                 $.ajax(
                     url: "/Order/GetOrderList",
                     type: "Get", 
                     contentType: "application/json; charset=utf-8",
                     dataType: "json",
                     success: function (data) 
                         console.log("succsss" + data);
                         //after getting the data, bind the DataTable.
                         var table = $("#example").DataTable(
                             "data": data,
                             "columns": [
                                 
                                     "className": 'details-control',
                                     "orderable": false,
                                     "data": null,
                                     "defaultContent": ''
                                 ,
                                  "data": "orderId" ,
                                  "data": "customer" ,
                                  "data": "orderDate" ,
                             ],
                             "order": [[0, 'desc']]
                         );
    
                         //Expand/Collapse the nested objects.
                         $('#example tbody').on('click', 'td.details-control', function () 
                             var tr = $(this).closest('tr');
                             var row = table.row(tr);
    
                             if (row.child.isShown()) 
                                 // This row is already open - close it
                                 row.child.hide();
                                 tr.removeClass('shown');
                             
                             else 
                                 // Open this row
                                 row.child(format(row.data())).show();
                                 tr.addClass('shown');
                             
                         );
                     ,
                     error: function (ex) 
                         console.log(ex);
                     
                 ); 
             );
         </script>
     
    

结果如下:

[注意]

如果遇到“table.row is not a function”错误,请将JQuery脚本中的dataTable()改为DataTable()。更多详细信息,请查看table.row is not a function 将数据绑定到 JQuery DataTable 插件时,请记住将属性的第一个字符更改为小写。

更多关于使用JQuery DataTable插件的详细信息,请查看the document。

【讨论】:

这正是我想做的,非常感谢。如果不是太多,如何搜索子行。【参考方案2】:

这是我完成此任务的一种相对简单的方法。

我使用“父”行下方的隐藏行来扩展完整的单元格计数,并通过父单元格中的 div 的单击事件显示/隐藏。此 div 包含属性 data-id 用于行的订单 ID 值,我使用该属性创建对子/隐藏行的引用(例如,detail_151)。当然,这假设父 ID 是唯一的。您可以在构建源 HTML 时添加这些值。

以我的 sn-p 为例。

// Add the .expand class click events once the page is loaded.
window.onload = e => 

  document.querySelectorAll('.expand').forEach(div => 

    div.addEventListener('click', e => 

      // Toggle the detail display.
      const detail = document.querySelectorAll(`#detail_$e.target.getAttribute('data-id')`)[0];
      if (detail.classList.contains('hide'))
        detail.classList.remove('hide');
      else
        detail.classList.add('hide');

    );

  );

body 
  font-size: 1em;


th,
td 
  position: relative;
  width: 125px;
  text-align: left;


.expand 
  position: absolute;
  font-size: 1.4em;
  margin-top: -5px;
  margin-left: -20px;
  color: green;
  font-weight: bold;
  cursor: pointer;


.hide 
  display: none;


.show 
  display: block;
<table style="margin-left: auto; margin-right: auto;">
  <thead>
    <tr>
      <th>OrderId</th>
      <th>Customer</th>
      <th>OrderDate</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>
        <div data-id="151" class="expand">+</div>151</td>
      <td>Customer21</td>
      <td>22.12.2020</td>
    </tr>
    <tr id="detail_151" class="hide">
      <td colspan="3">
        <table>
          <tr>
            <th>Kimlik</th>
            <th>Detail</th>
            <th>Color</th>
            <th>Qty</th>
          </tr>
          <tr>
            <td>2114</td>
            <td>Product-14</td>
            <td>Green</td>
            <td>3</td>
          </tr>
          <tr>
            <td>2358</td>
            <td>Product-48</td>
            <td>Yellow</td>
            <td>2</td>
          </tr>
          <tr>
            <td>2365</td>
            <td>Product-08</td>
            <td>Red</td>
            <td>6</td>
          </tr>
          <tr>
            <td>2371</td>
            <td>Product-33</td>
            <td>Red</td>
            <td>1</td>
          </tr>
        </table>
      </td>
    </tr>
    <tr>
      <td>
        <div data-id="155" class="expand">+</div>155</td>
      <td>Customer18</td>
      <td>22.12.2020</td>
    </tr>
    <tr id="detail_155" class="hide">
      <td colspan="3">
        <table>
          <tr>
            <th>Kimlik</th>
            <th>Detail</th>
            <th>Color</th>
            <th>Qty</th>
          </tr>
          <tr>
            <td>2019</td>
            <td>Product-11</td>
            <td>Red</td>
            <td>3</td>
          </tr>
          <tr>
            <td>2110</td>
            <td>Product-17</td>
            <td>Blue</td>
            <td>5</td>
          </tr>
        </table>
      </td>
    </tr>
  </tbody>
</table>

【讨论】:

截图只是我的目标的一个说明,成千上万的数据将来自数据库

以上是关于数据表中的多个子行,来自asp.net核心中sql server的数据的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core MVC 中的 TreeView(来自 SQL 的数据)

asp.net 核心中的红隼

jquery 循环和分配来自 Asp.net 核心 Razor 页面 foreach 的数据

无法从 docker windows 容器中的 asp.net 核心应用程序连接到主机数据库

从 ASP.NET 中的 SQL 数据库中检索 HTML 代码

错误:来自 ASP.NET 的 UPDATE 查询中的“没有为一个或多个必需参数提供值”