2016年5月30日 星期一

LINQ 讀取 ADO.Net DataTable 內容

能夠將我們習慣的 DataTable 透過 Linq 來進行查詢,是一件很幸福的事情。基本上,只要記得兩個語法就可以針對  DataTable 來操作。

第一個是:把 DataTable 轉為 IEnumerable<T>
使用 AsEnumerable() 來完成

第二個是:把 Linq 查詢的結果存成 DataTable。
使用 CopyToDataTable<DataRow>() 來完成


可以透過下面範例來練習:

//抓取 DataTable dtDetail 的資料
DataTable dtDetail=oT.getDataById(strID).Tables[0];

//透過 AsEnumerable() 將 DataTable 轉為 IEnumerable<T> 格式
IEnumerable<DataRow> queryDetail = from d in dtDetail.AsEnumerable()
where int.Parse( d.Field<string>("sud_salesdate") ) > int.Parse("20160101")
select d;

//將查詢結果存成 DataTable
DataTable dtResult = queryDetail.CopyToDataTable<DataRow>();

2016年5月11日 星期三

Reporting Service 報表升級的問題

過去曾用過 VS2008 開發過好幾支 Reporting Service Server Report,因為有需求將這些報表改成 Local Report,而開發工具則是升級為 VS2010。比對了這兩個版本的差異,是副檔名不同,VS2008 的副檔名是 *.rdl ,VS2010 的副檔名則是 *.rdlc。所以,只要在副檔名加個 c 應該就可以了吧!

於是,我將 Certificate_Test.rdl 複製到 VS2010 的開發資料夾,再把檔名改成  Certificate_Test.rdlc, 並用 VS2010 去開啟它。


看起來,還好嘛,就讓他自己去轉換就好,於是按了「確定」!


看到「One or more errors encountered while loading the designer. The errors are listed below.」錯誤訊息,然後   就  ...   傻住了...   真的傻住了!

透由 Polly 的協助,參考了一篇由 prakash rao 所發表的文章「Microsoft Report Designer : Do you want to convert this report to RDLC 2008 format? Please click OK to proceed or Cancel to open it in the XML editor. 」,一步一步完成了轉換工作。

首先,從傻住的頁面開始,點選 「Edit Code」,就可以看到用 XML 所表示的內容。其實,不管是 *.rdl 也好, *.rdlc 也好,報表的內容都是用 XML 來定義的。在報表升級開發工具升級的過程中,難免會新增或刪除了 XML 的標籤或元素。先看到的,就是升級後被刪除的 「ReportSection」與「ReportSections」,可以用 Ctrl+F 打開搜尋視窗,找到那兩個標籤,因為每個標籤同時都會有起始與結束,所以都要刪除。



然後,再到最前面的第二行 Report xmlns



將它改成:

<Report xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner" xmlns="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition">


最後就按「存檔」。接著把剛剛編輯的報表都關掉,然後重新點選 Certificate_Tesst.rdlc,就可以看到正常的報表了。

因為我改成使用 Local Report 的方式,原先要傳給 Server Report 的參數已經不需要了,要記得到 Report Data 裡的 Parameters 刪除。


此外,因為我已不再使用 DataSource1,所以也順便刪除,然後在新增一個 DataSet。你可能會發現, DataSource1 竟然刪不掉,別擔心,點開你的 DataSource1,會發現裡面還會有 DataSet,先把裡面的所有 DataSet 都刪掉,然後就可以刪除 DataSource1 了。


參考:
01:Microsoft Report Designer : Do you want to convert this report to RDLC 2008 format? Please click OK to proceed or Cancel to open it in the XML editor. 

2016年5月4日 星期三

LocalReport 報表合併後變成空白

我使用了 Local Report 產生了好幾張 PDF  報表,接著想要將他們合併成一份報表。這時,我選用了 Aspose 這工具,多年前,我曾經用過他,一直合作愉快。

「昨是而今非」,是今天最好的註解。透過 Aspose 合併後的 PDF 檔案,裡面竟然是空白的,我發誓,還沒合併前,每一份 PDF 的確是有資料的啊!

原來,我的 PDF 是透過 VS2010 所產生的,報表的產生語法如下:


byte[] tBytes = viewer.LocalReport.Render(pType, null, out tMimeType, out tEncoding, out tExtension, out tStreamids, out tWarnings);


Render() 裡的第二個參數,本應該放 deviceInfo,我原先覺得很像沒什麼好設定的,於是就簡單放了 null。在「PDF Sharp can't handle SQL Server 2008 PDF reports」文章中提到,Reporting Service 2008 之後,開始有了 HumanReadablePDF 這個參數設定,指示是否 PDF 匯出時應該被壓縮,使得檔案更容易閱讀,預設值為 False。因為我把 devideInfo 設為 null,所以 HumanReadablePDF = false。這個致命的關鍵設定,造成讓 Aspose 在合併 PDF 時,無法正確的取得原先 PDF 內容。所以,要手動去定義 HumanReadablePDF,並將它設為 true。

透過下面語法,就可以完成:
string devInfo = @"<DeviceInfo><HumanReadablePDF>True</HumanReadablePDF></DeviceInfo>";
byte[] tBytes = viewer.LocalReport.Render("PDF", devInfo, out tMimeType, out tEncoding, out tExtension, out tStreamids, out tWarnings);




參考:

01:PDF Sharp can't handle SQL Server 2008 PDF reports
02:[SQL Server 2008R2][SSRS] URL Access 報表轉譯格式設定(二)

2016年5月3日 星期二

使用 VS2010 在 Console Application 下 產生 LocalReport

01.增加參考。包含

Microsoft.ReportViewer.WebForms (Ver.10.0)
Microsoft.ReportViewer.Common (Ver.10.0)

※ 注意,ReportViewer 版本要選 10.0

System.Web (Ver 2.0)
System.Web.Extensions (Ver 3.5)




02.建立一個空白報表,取名為 Report1.rdlc。


03.建立一個 DataSet,取名為 dsTest.xsd


04.在 dsTest.xsd 建立一個查詢。選擇 Add → TableAdapter




建立一個新的 DB 連線資訊。


這裡是說,剛剛的連線字串因為有帳號密碼,屬於敏感資料,是否要在連線資訊裡顯示,選擇「是」。


針對剛剛的連線,取個名字。


挑選要查詢的方式,因為待會要自己寫 SQL,所以選「Use SQL statements」


這裡只是做個簡單的查詢指令,然後可以直接按「Finish」來完成。


存檔後,先重先編譯一下專案。Build → ReBuild Solution。

05.回到 Report1.rdlc。到 ReportData ,如果看不到 ReportData,則到 View → Report Data 可以找到。


選擇 New→DataSet


在 Data Source 挑選 dsTest,然後點選 「OK」


將 DataSet1 的 CustCName 拖拉到 報表 內文中,然後存檔。



有個小地方別忘了,就是將 Report1.rdlc 屬性裡的  Copy  to Output Director 設為 「Copy Always」。這樣,當程式被編譯時,自動會將報表複製到 BIN 資料夾。




06. 參考了這篇「[C#]透過ReportViewer將報表另存成檔案」,將 Program.cs 程式改寫如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Reporting.WebForms;
using System.Data.SqlClient;
using System.Data;
using System.IO;


class Program
{
 static void Main(string[] args)
 {
  ExportReport("PDF");
 }

 public static void ExportReport(string pType)
 {

  Microsoft.Reporting.WebForms.Warning[] tWarnings;
  string[] tStreamids;
  string tMimeType;
  string tEncoding;
  string tExtension;


  // Setup the report viewer object and get the array of bytes
  ReportViewer viewer = new ReportViewer();
  viewer.ProcessingMode = ProcessingMode.Local;
  viewer.LocalReport.ReportPath = "Report1.rdlc";

  string DBConnection = @"DATABASE=CarISC;Server=140.11.1.1,5555;User ID=account;Password=pwd";
  string sql = @"select top 1 * from Customer";
  SqlConnection conn = new SqlConnection(DBConnection);
  SqlCommand SqlCmd = new SqlCommand(sql, conn);
  SqlDataAdapter adapter = new SqlDataAdapter(SqlCmd);
  DataSet ds = new DataSet();
  conn.Open();
  adapter.Fill(ds);
  conn.Close();

  DataTable tDt = ds.Tables[0];



  viewer.LocalReport.DataSources.Clear();
  viewer.LocalReport.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource("DataSet1", tDt));
  viewer.LocalReport.Refresh();


  //呼叫ReportViewer.LoadReport的Render function,將資料轉成想要轉換的格式,並產生成Byte資料
  byte[] tBytes = viewer.LocalReport.Render(pType, null, out tMimeType, out tEncoding, out tExtension, out tStreamids, out tWarnings);

  //將Byte內容寫到Client

  using (FileStream fs = new FileStream(@"D:\ProjTest\MyTest.pdf", FileMode.Create))
  {
   fs.Write(tBytes, 0, tBytes.Length);
   fs.Close();
  }


 } 
}


這樣,就能夠產生報表了(位於 D:\ProjTest\MyTest.pdf)。

在測試過程中,曾經發生「報表定義具有無效的目標命名空間 'http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition'」這錯誤,經過「RDLC命名空间引用错误的解决方法」的介紹,發現是自己所參考的Microsoft.ReportViewer.WebForms 版本錯誤所致,所以在引用參考時,要選對版本。

後記:

以上測試程式的環境為 .Net FrameWork 3.5,我在 .Net FrameWork 2.0 發現找不到參考 「Microsoft.ReportViewer.WebForms」,但卻有 「Microsoft.ReportViewer.WinForms」。於是我改成參考 「Microsoft.ReportViewer.WinForms」,也可以成功。

只是要多參考一個:「System.Windows.Forms」

而 progarm.cs 有兩處要修改:

1. Microsoft.Reporting.WebForms.Warning[] tWarnings;
   改成
   Microsoft.Reporting.WinForms.Warning[] tWarnings;

2.viewer.LocalReport.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource("DataSet1", tDt));
   改成
viewer.LocalReport.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("DataSet1", tDt));

補充:
01:如果有需要合併多張報表,可參考「LocalReport 報表合併後變成空白」。




參考:
01:[C#]透過ReportViewer將報表另存成檔案
02:如何製作LocalReport-進階版(下)
03:如何製作LocalReport-簡易版(上)
04:Rendering RDLC to pdf output console application
05:RDLC命名空间引用错误的解决方法