为特定行值重复特定列

时间:2016-03-29 14:08:23

标签: c# datatable

我对C#比较新。我将在超市中举例说明。

我目前有一个表,每个唯一的StoreID / Product组合都有一行,使用此布局:

StoreID  Store   Country   Product   In-Stock?  Count  SalePrice
   1     Tesco   UK        Soap      Yes        10     £2.99
   2     Asda    UK        Soap      No         0      £0.00
   3     Aldi    UK        Soap      Yes        15     £2.98
   1     Tesco   UK        Cheese    Yes        10     £4.72
   2     Asda    UK        Cheese    No         0      £0.00
   3     Aldi    UK        Cheese    Yes        15     £3.57

我想重新安排此表,以便结果显示如下:

                                  Cheese                        Soap            
StoreID  Store  Country  In-Stock? Count  SalePrice  In-Stock? Count  SalePrice
  1      Tesco  UK       Yes       10     £4.72      Yes       10     £2.99    
  2      Asda   UK       No        0      £0.00      No        0      £2.49   
  3      Aldi   UK       Yes       15     £3.57      Yes       15     £2.98    

您会看到我每个唯一商店只有一行(由storeID定义),但现在每个产品都会重复与产品相关的三个(和肥皂)。

2 个答案:

答案 0 :(得分:1)

好的,所以这是一个非常简单的例子,说明如何开始做这样的事情。 (如果你愿意的话,你可能会变得非常强大,但这超出了范围)如果你喜欢这个一般的想法,我建议使用LINQ to SQL并完全跳过数据表转换的东西。 免责声明: in try / catch评论或评论告诉我为什么有些不好主意,使用ORM等等)这是演示代码,仅用于展示如何思考没有任何第三方组件解决此问题。生产代码必须处理缺少的ID,错误处理,正确的布局和CSS样式,以及更多我不会涉及的内容。

<强> Test.aspx文件

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Test.aspx.cs" Inherits="WebApplication2.Test" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

        <asp:GridView ID="GridView1" runat="server">
        </asp:GridView>

       <div runat="server" id="container">

        </div>
    </div>
    </form>
</body>
</html>

<强>代码隐藏

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication2
{
    public class MyStoreObject
    {
        public int StoreID { get; set; }
        public string StoreName { get; set; }
        public string Country { get; set; }
        public string Product { get; set; }
        public bool InStock { get; set; }
        public Int16 Count { get; set; }
        public double Price { get; set; }
    }

    public partial class Test : System.Web.UI.Page
    {
        protected DataTable dtStoreInfo = new DataTable();
        protected List<MyStoreObject> MyStoreObjects = new List<MyStoreObject>();

        //protected
        protected void Page_Init(object sender, EventArgs e)
        {
            dtStoreInfo.Columns.AddRange(new DataColumn[] {
                new DataColumn("StoreID", typeof(int)),
                new DataColumn("StoreName", typeof(string)),
                new DataColumn("Country", typeof(string)),
                new DataColumn("Product", typeof(string)),
                new DataColumn("InStock", typeof(bool)),
                new DataColumn("Count", typeof(Int16)),
                new DataColumn("Price", typeof(double))
            });

        }
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                FillDatasource();
                TransformDataSourceToObjects();                

                // here's all the things
                GridView1.DataSource = MyStoreObjects;
                GridView1.DataBind();

                // we need to break this down into a multi-column layout; the store name, id, and country in one section
                // then additional sections per product that have the prod as the header, the in-stock, count, and price in body
                // you can create whatever controls you need to display this information

                var MyStoreObjects_Stores = MyStoreObjects.Select(x => new { x.StoreID, x.StoreName, x.Country }).Distinct();
                var MyStoreObjects_Products = MyStoreObjects.Select(x => x.Product).Distinct();

                Table displayTable = new Table();
                TableRow tRow = new TableRow();
                TableCell tCell = new TableCell();
                tRow.Cells.Add(tCell);
                displayTable.Rows.Add(tRow);

                GridView oGridViewMain = new GridView();
                oGridViewMain.DataSource = MyStoreObjects_Stores;
                oGridViewMain.DataBind();
                tCell.Controls.Add(oGridViewMain);

                foreach (var product in MyStoreObjects_Products)
                {
                    var resultByProd = MyStoreObjects.Where(x => x.Product == product);

                    GridView gvProduct = new GridView();
                    gvProduct.DataSource = resultByProd;
                    gvProduct.DataBind();
                    TableCell tCellProd = new TableCell();
                    tCellProd.Controls.Add(gvProduct);
                    tRow.Cells.Add(tCellProd);
                }

                container.Controls.Add(displayTable);
            }
        }

        private void FillDatasource()
        {
            // assume this comes from a database query eventually, maybe from a dataadapter fill or whatever
            dtStoreInfo.Rows.Add(new object[] { 1, "Tesco", "UK", "Soap", true, 10, 2.99 });
            dtStoreInfo.Rows.Add(new object[] { 2, "Asda", "UK", "Soap", false, 0, 0.00 });
            dtStoreInfo.Rows.Add(new object[] { 3, "Aldi", "UK", "Soap", true, 15, 2.98 });
            dtStoreInfo.Rows.Add(new object[] { 1, "Tesco", "UK", "Cheese", true, 10, 4.72 });
            dtStoreInfo.Rows.Add(new object[] { 2, "Asda", "UK", "Cheese", false, 0, 0.00 });
            dtStoreInfo.Rows.Add(new object[] { 3, "Aldi", "UK", "Cheese", true, 15, 3.57 });

        }

        private void TransformDataSourceToObjects()
        {
            // this would ideally come from LINQ to SQL or another ORM, presented simplified here for demo only
            foreach (DataRow row in dtStoreInfo.Rows)
            {
                MyStoreObjects.Add(new MyStoreObject()
                {
                    StoreID = (Int32)row["StoreID"],
                    StoreName = (string)row["StoreName"],
                    Country = (string)row["Country"],
                    Product = (string)row["Product"],
                    InStock = (bool)row["InStock"],
                    Count = (Int16)row["Count"],
                    Price = (double)row["Price"]
                });
            }
        }
    }
}

答案 1 :(得分:0)

我在尝试检索所需输出时发现的主要问题是数据表不能有多个具有相同名称的列。所以这里是一个非常简单的概述,我如何检索正确格式的数据:

  1. 检索唯一项目列表。
  2. 对于每个项目,使用where子句运行查询副本,将数据限制为单个项目。
  3. 为每个重复列指定唯一名称(发送到此方法的“前缀”是唯一项目名称):

    DataTable GetUniqueColumnNames(DataTable table, string prefix)
    {
        table.Columns["InStore"].ColumnName = prefix + " - In-Stock?";
        table.Columns["Vanda"].ColumnName = prefix + " - Count";
        table.Columns["Cattleya"].ColumnName = prefix + " - Price";
    
        return table;
    }
    
  4. 使用StoreID作为表主键合并每个项目表(具有唯一的项目相关列)。

  5. 这提供了以下内容:

    StoreID  Store  Country  Cheese-In-Stock?  Cheese-Count  Cheese-Price  Soap-In-Stock? Soap-Count  Soap-Price
      1      Tesco  UK       Yes               10            £4.72         Yes            10           £2.99    
      2      Asda   UK       No                0             £0.00         No             0            £2.49   
      3      Aldi   UK       Yes               15            £3.57         Yes            15           £2.98    
    

    不可否认,它并不像我希望的那样漂亮 - 但是它完成了这项工作!