iT邦幫忙

4

弄一個公版的Excel匯出專用功能

  • 分享至 

  • xImage

上次摸懂動態Class後~
https://ithelp.ithome.com.tw/questions/10215682

我在想有沒有更簡單的動態欄位匯出~

後來想到以前寫ASP、PHP的模擬資料庫介面寫法

也就是根據資料庫帶出底下的資料表,

再根據資料表帶出欄位的名稱、屬性、預設值等...

果然在MVC版本其實也是可以迴圈動態抓資料表的欄位名 (LinQ 沒辦法)

那就更簡單了~只要一個公版Excel匯出功能頁

其他功能頁的匯出功能~直接套用此頁匯出就好

我的寫法如下,在資料庫新增 自訂函數、預存程序(各種匯出欄位的輸出)

首先在資料庫新增 自訂函數 Split 切割字串用

create function dbo.Set_Split(
	@Parameter nvarchar(max)
	,@Index int
)
Returns nvarchar(max)
as
begin
	-- 或可用 String_Split 但要2016版本以上才可以使用

	declare @i int = 0
	declare @Char_Start int = 1
	declare @Char_End int = 1
	declare @Char_Length int = 0
	declare @Length int = len(@Parameter)
	declare @Count int = @Length - len(Replace(@Parameter,',',''))
	declare @Str nvarchar(max)

	while(@i <= @Count)
	begin
		set @Char_End = CharIndex(',',@Parameter,@Char_Start)

		if(@i=@Count)
		begin
			set @Char_End = @Length + 1
		end
		set @Char_Length = @Char_End - @Char_Start

		if(@Index=@i)
		begin
			set @Str = SubString(@Parameter,@Char_Start,@Char_Length)
		end
		if(@Str='')
		begin
			set @Str = null
		end

		set @Char_Start = @Char_End + 1
		set @i = @i + 1
	end

	Return @Str
end

然後自訂要匯出的預存程序

create procedure Excel_Students
@Parameter nvarchar(max) = null
as
begin
	--自訂匯出的預存程序 學生資料表
    
	--搜索條件
	declare @Id nvarchar(10) = dbo.Set_Split(@Parameter,0)
	declare @Name nvarchar(10) = dbo.Set_Split(@Parameter,1)
	declare @Sex nvarchar(10) = dbo.Set_Split(@Parameter,2)
	
	--要匯出的資料表
	select Id 學生編號
	,Name 姓名
	,Sex 性別
    from Students
	where 1=1
	and (@Id is null or @Id = Id)
	and (@Name is null or Name like N'%' + @Name + '%')
	and (@Sex is null or @Sex = Sex)

end

最後是公版的Excel匯出頁

using System.Web.Mvc;
using System.IO;
using WebMvcEF.Models;
using NPOI.HSSF.UserModel;

//測試區 2024-05-25 By Jerwei
namespace WebMvcEF.Controllers.RPT
{
    public class ExcelController : Controller
    {
        /// <summary>
        /// 進入匯出Excel
        /// </summary>
        /// <returns></returns>
        public ActionResult ReportSet(string ProcedureName,string Parameters = "", string FileName= "資料")
        {
            //建立Excel空白檔案
            var hssfworkbook = new HSSFWorkbook(); //建立活頁簿
            var sheet = hssfworkbook.CreateSheet("sheet"); //建立sheet

            //設定樣式
            //var headerStyle = hssfworkbook.CreateCellStyle();
            //var headerfont = hssfworkbook.CreateFont();
            //headerStyle.Alignment = HorizontalAlignment.Center; //水平置中
            //headerStyle.VerticalAlignment = VerticalAlignment.Center; //垂直置中
            //headerfont.FontName = "微軟正黑體";
            //headerfont.FontHeightInPoints = 20;
            //headerfont.Boldweight = (short)FontBoldWeight.Bold;
            //headerStyle.SetFont(headerfont);

            //新增標題列
            //sheet.CreateRow(0); //需先用CreateRow建立,才可通過GetRow取得該欄位
            //sheet.AddMergedRegion(new CellRangeAddress(0, 1, 0, 2)); //合併1~2列及A~C欄儲存格
            //sheet.GetRow(0).CreateCell(0).SetCellValue("測試");
            //sheet.GetRow(0).GetCell(0).CellStyle = headerStyle; //套用樣式

            // CreateRow(2) 建立第3列
            // GetRow(2) 取得第3列位置
            // CreateCell(0) 建立第0欄
            // SetCellValue("學生姓名") 填入資料

            var Sql = @"
                if(OBJECT_ID('" + ProcedureName.Replace("'","") + @"','P')) is not null
                begin
	                exec " + ProcedureName.Replace("'","") + @" '" + Parameters.Replace("'", "''") + @"'
                end
                else
                begin
	                select N'找不到預存程序!' '異常錯誤!'
                end
            ";
            var dt = MSSQLHelper.GetTable(Sql, System.Data.CommandType.Text);
            //寫入欄位名稱
            var rowIndex = 0;
            for (var i = 0; i < dt.Columns.Count ; i++)
            {
                if (i == 0)
                {
                    sheet.CreateRow(rowIndex).CreateCell(i).SetCellValue(dt.Columns[i].ToString());
                }
                else
                {
                    sheet.GetRow(rowIndex).CreateCell(i).SetCellValue(dt.Columns[i].ToString());
                }
            }
            foreach (System.Data.DataRow dr in dt.Rows)
            {
                //寫入欄位資料
                rowIndex++;
                for (var i = 0; i < dt.Columns.Count; i++)
                {
                    if (i == 0)
                    {
                        sheet.CreateRow(rowIndex).CreateCell(i).SetCellValue(dr[i].ToString());
                    }
                    else
                    {
                        sheet.GetRow(rowIndex).CreateCell(i).SetCellValue(dr[i].ToString());
                    }
                }
            }

            var excelDatas = new MemoryStream(); //建立IO檔案資料流
            hssfworkbook.Write(excelDatas); //將Excel資料寫入資料流

            return File(excelDatas.ToArray(), "application/vnd.ms-excel", string.Format(FileName + $".xls"));
        }

    }

}

rogeryao iT邦超人 7 級 ‧ 2024-05-25 14:39:32 檢舉
放到技術文章吧
哈~我在期待有沒有更好的優化😂😂😂
alien663 iT邦研究生 3 級 ‧ 2024-05-27 09:31:22 檢舉
自肥一下,我自己寫的Excel零件。
我是把Excel的匯入匯出獨立出來成為一個Library,然後提供不同接口讓他可以自由轉換,面對不同的狀況,就可以透過組合不同的零件來達成需求。
例如你要從DB轉成Excel匯出,就可以直接透過DataTable來做轉換,相較於直接把Excel和資料庫兩部分綁定,我覺得個別抽出來做更具有靈活性。
https://github.com/Alien663/Lib-Cscharp
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

1
breezy89757
iT邦新手 5 級 ‧ 2024-05-28 00:08:39
最佳解答

假如是要將DB的資料匯出成excel可以試試看Dapper+MiniExcel,以下程式碼為.Net Core的主控台應用程式

using Dapper;
using System.Data.SqlClient;
using MiniExcelLibs;
using var connection = new SqlConnection("Data Source=(LocalDb)\\MSSQLLocalDB;Initial Catalog=IThomeSample;");
var result = await connection.QueryAsync("SELECT * FROM Students");
MiniExcel.SaveAs("Students.xlsx", result);

https://ithelp.ithome.com.tw/upload/images/20240528/201671588C6IQOlwn0.png
https://ithelp.ithome.com.tw/upload/images/20240528/20167158hFVd18Agjg.png

0
ericoaitken
iT邦見習生 ‧ 2024-10-07 11:40:12

我發現這是更有效的方法之一,允許多個匯出函數重複使用單一 Excel 匯出表 geometry dash deadlocked 從而提高程式碼的可重複使用性和更好的可維護性。

我要發表回答

立即登入回答