feat: fmBPSN GridView 改用 ObjectDataSource 並採 KEYSET 分頁

- BpsnDAC 新增 SelectPage/SelectCount/SelectBPENOIndex

- SelectPage 採 KEYSET:先在窄集合 BPSNView 算 ROWID,再 join 該頁明細

- SelectCount/SelectBPENOIndex 改用窄集合(免 join)

- fmBpsn.ascx dsBPSNGrid 改 ObjectDataSource(EnablePaging)

- fmBpsn.ascx.cs 調整 Search/Selected/OnInit

- 修復 BpsnDAC.cs 亂碼註解並改存 UTF-8 BOM

- 新增 Doc/GridView改用ObjectDataSource計畫.md(盤點、計畫、效能比較)
This commit is contained in:
2026-09-10 10:29:18 +08:00
parent 577060bc78
commit 9adbcfe0a4
4 changed files with 422 additions and 99 deletions
+243 -15
View File
@@ -1,14 +1,16 @@
using System;
using System;
using System.Data;
using System.Data.Common;
using System.Configuration;
using System.Text;
using System.Collections.Generic;
using System.ComponentModel;
using Wellan.Data;
/// <summary>
/// 員工資料的資料處理類別
/// 員工資料的資料處理類別
/// </summary>
[DataObject(true)]
public class BpsnDAC : Wellan.Data.BPSN_DAC
{
private DbCommand cmdSelect;
@@ -115,7 +117,7 @@ public class BpsnDAC : Wellan.Data.BPSN_DAC
}
/// <summary>
/// 取得人員目前派駐專案
/// 取得人員目前派駐專案
/// </summary>
/// <param name="bpeno"></param>
/// <returns></returns>
@@ -125,7 +127,7 @@ public class BpsnDAC : Wellan.Data.BPSN_DAC
}
/// <summary>
/// 取得人員目前派駐專案
/// 取得人員目前派駐專案
/// </summary>
/// <param name="bpeno"></param>
/// <returns></returns>
@@ -154,7 +156,7 @@ public class BpsnDAC : Wellan.Data.BPSN_DAC
}
/// <summary>
/// 取得人員目前派駐地點
/// 取得人員目前派駐地點
/// </summary>
/// <param name="bpeno"></param>
/// <returns></returns>
@@ -164,7 +166,7 @@ public class BpsnDAC : Wellan.Data.BPSN_DAC
}
/// <summary>
/// 取得人員目前派駐地點
/// 取得人員目前派駐地點
/// </summary>
/// <param name="bpeno"></param>
/// <returns></returns>
@@ -182,7 +184,7 @@ public class BpsnDAC : Wellan.Data.BPSN_DAC
}
/// <summary>
/// 取得人員電子郵件
/// 取得人員電子郵件
/// </summary>
/// <param name="bpeno"></param>
/// <returns></returns>
@@ -197,7 +199,7 @@ public class BpsnDAC : Wellan.Data.BPSN_DAC
}
/// <summary>
/// 取得人員電子郵件2
/// 取得人員電子郵件2
/// </summary>
/// <param name="bpeno"></param>
/// <returns></returns>
@@ -212,10 +214,10 @@ public class BpsnDAC : Wellan.Data.BPSN_DAC
}
/// <summary>
/// 取得某日期人員所屬公司名稱
/// 取得某日期人員所屬公司名稱
/// </summary>
/// <param name="bpeno">員工編號</param>
/// <param name="date">日期</param>
/// <param name="bpeno">員工編號</param>
/// <param name="date">日期</param>
/// <returns></returns>
public List<string> GetCompanyByDate(string bpeno, DateTime date)
{
@@ -243,7 +245,7 @@ public class BpsnDAC : Wellan.Data.BPSN_DAC
}
/// <summary>
/// 取得人員到職日期
/// 取得人員到職日期
/// </summary>
/// <param name="bpeno"></param>
/// <returns></returns>
@@ -258,7 +260,7 @@ public class BpsnDAC : Wellan.Data.BPSN_DAC
}
/// <summary>
/// 取得人員離職日期
/// 取得人員離職日期
/// </summary>
/// <param name="bpeno"></param>
/// <returns></returns>
@@ -287,12 +289,238 @@ public class BpsnDAC : Wellan.Data.BPSN_DAC
}
/// <summary>
/// 取出某日期在職的員工
/// 取出某日期在職的員工
/// </summary>
/// <param name="date">日期</param>
/// <param name="date">日期</param>
/// <returns></returns>
public DataTable GetOnBoardEmployee(DateTime date)
{
return Query.Select(Query.NewCommand("SELECT * FROM BPSNView WHERE dbo.EmployeeOnboard(BPENO, @DATE) = 1"));
}
private const string GridSelectColumns =
@" A2.*
, B.RAPYN, C.BPPYM RAPYNX, B.RABRH, D.BSSCR RABRHX, B.RAJNO, E.BPJME RAJNOX, B.RACNO
, F.BPCME RACNOX, ISNULL(H.RPCPY, G.RPCPY) AS RPCPY ";
// 只 join 該頁明細用 (明細主表為 A2)
private const string GridDetailJoins =
@" LEFT OUTER JOIN RASN B ON A2.BPENO=B.RANUM AND (B.RAEDT IS NULL OR (B.RASDT <= @TODAY AND B.RAEDT >= @TODAY))
LEFT OUTER JOIN BPAA C ON B.RAPYN=C.BPPYN
LEFT OUTER JOIN BCLS D ON D.BSCLS=B.RABRH AND D.BSPAR='BPSNBRH'
LEFT OUTER JOIN BPJA E ON E.BPPYN=B.RAPYN AND E.BPJNO=B.RAJNO
LEFT OUTER JOIN BPJB F ON F.BPPYN=B.RAPYN AND F.BPJNO=B.RAJNO AND F.BPCNO=B.RACNO
LEFT OUTER JOIN RPIR G ON A2.BPENO=G.RPENO AND G.RPREN=(SELECT MAX(RPREN) FROM RPIR WHERE RPENO=A2.BPENO)
LEFT OUTER JOIN RPIB H ON G.RPREN=H.RPREN AND H.RPITM=(SELECT MAX(RPITM) FROM RPIB WHERE RPREN=H.RPREN) ";
/// <summary>
/// 人員資料 Grid 分頁查詢
/// </summary>
[DataObjectMethod(DataObjectMethodType.Select)]
public DataTable SelectPage(
int startRowIndex,
int maximumRows,
string BPENO,
string BPNME,
string BPENM,
string BPIDN,
string BPEDY_TYPE,
string BPDPT_TYPE,
string BPSDY1,
string BPSDY2,
string BPEDY1,
string BPEDY2,
bool canSearch,
string userId)
{
DbCommand cmd = Query.NewCommand();
StringBuilder filter = new StringBuilder();
BuildGridFilter(filter, cmd, BPENO, BPNME, BPENM, BPIDN, BPEDY_TYPE, BPDPT_TYPE, BPSDY1, BPSDY2, BPEDY1, BPEDY2, canSearch, userId);
// 先在窄集合 (BPSNView) 依 BPENO 排序計算 ROWID,取出該頁的 BPENO 後,
// 才 join 明細表,避免深頁時對整個 join 結果計算 ROW_NUMBER()。
cmd.CommandText = String.Format(
@"SELECT {0}
FROM
(
SELECT A.BPENO, ROW_NUMBER() OVER (ORDER BY A.BPENO) AS ROWID
FROM BPSNView A WHERE 1=1 {1}
) R
JOIN BPSNView A2 ON A2.BPENO = R.BPENO
{2}
WHERE R.ROWID BETWEEN @STARTROWINDEX + 1 AND @STARTROWINDEX + @MAXIMUMROWS
ORDER BY R.ROWID",
GridSelectColumns, filter.ToString(), GridDetailJoins);
cmd.Parameters.Add(Query.NewParameter("STARTROWINDEX", startRowIndex));
cmd.Parameters.Add(Query.NewParameter("MAXIMUMROWS", maximumRows));
return Query.Select(cmd);
}
/// <summary>
/// 人員資料 Grid 查詢筆數
/// </summary>
[DataObjectMethod(DataObjectMethodType.Select)]
public int SelectCount(
string BPENO,
string BPNME,
string BPENM,
string BPIDN,
string BPEDY_TYPE,
string BPDPT_TYPE,
string BPSDY1,
string BPSDY2,
string BPEDY1,
string BPEDY2,
bool canSearch,
string userId)
{
DbCommand cmd = Query.NewCommand();
StringBuilder filter = new StringBuilder();
BuildGridFilter(filter, cmd, BPENO, BPNME, BPENM, BPIDN, BPEDY_TYPE, BPDPT_TYPE, BPSDY1, BPSDY2, BPEDY1, BPEDY2, canSearch, userId);
cmd.CommandText = String.Format("SELECT COUNT(*) FROM BPSNView A WHERE 1=1 {0}", filter.ToString());
return WDAC.GetInt32Value(Query.ExecuteScalar(cmd));
}
/// <summary>
/// 取得指定人員編號在查詢結果中的序號 (0 起算)
/// </summary>
public int SelectBPENOIndex(
string targetBPENO,
string BPENO,
string BPNME,
string BPENM,
string BPIDN,
string BPEDY_TYPE,
string BPDPT_TYPE,
string BPSDY1,
string BPSDY2,
string BPEDY1,
string BPEDY2,
bool canSearch,
string userId)
{
DbCommand cmd = Query.NewCommand();
StringBuilder filter = new StringBuilder();
BuildGridFilter(filter, cmd, BPENO, BPNME, BPENM, BPIDN, BPEDY_TYPE, BPDPT_TYPE, BPSDY1, BPSDY2, BPEDY1, BPEDY2, canSearch, userId);
cmd.CommandText = String.Format(
@"SELECT ROWID - 1 FROM
(
SELECT A.BPENO, ROW_NUMBER() OVER (ORDER BY A.BPENO) AS ROWID
FROM BPSNView A WHERE 1=1 {0}
) AS TMP WHERE BPENO = @TARGET",
filter.ToString());
cmd.Parameters.Add(Query.NewParameter("TARGET", targetBPENO));
object o = Query.ExecuteScalar(cmd);
return (o is Int32 || o is Int64) ? WDAC.GetInt32Value(o) : -1;
}
/// <summary>
/// 組出人員資料 Grid 的查詢條件 (與舊 AddSearch 行為一致)
/// </summary>
private void BuildGridFilter(
StringBuilder sb,
DbCommand cmd,
string BPENO,
string BPNME,
string BPENM,
string BPIDN,
string BPEDY_TYPE,
string BPDPT_TYPE,
string BPSDY1,
string BPSDY2,
string BPEDY1,
string BPEDY2,
bool canSearch,
string userId)
{
cmd.Parameters.Add(Query.NewParameter("TODAY", DateTime.UtcNow.AddHours(8).Date));
if (!canSearch)
{
if (!string.IsNullOrEmpty(userId))
{
sb.Append(" AND BPENO LIKE @BPENO1 ");
cmd.Parameters.Add(Query.NewParameter("BPENO1", userId + "%"));
}
return;
}
if (!string.IsNullOrEmpty(BPENO))
{
sb.Append(" AND BPENO LIKE @BPENO1 ");
cmd.Parameters.Add(Query.NewParameter("BPENO1", BPENO + "%"));
}
if (!string.IsNullOrEmpty(BPNME))
{
sb.Append(" AND BPNME LIKE @BPNME1 ");
cmd.Parameters.Add(Query.NewParameter("BPNME1", BPNME + "%"));
}
if (!string.IsNullOrEmpty(BPENM))
{
sb.Append(" AND BPENM LIKE @BPENM1 ");
cmd.Parameters.Add(Query.NewParameter("BPENM1", BPENM + "%"));
}
if (!string.IsNullOrEmpty(BPIDN))
{
sb.Append(" AND BPIDN LIKE @BPIDN1 ");
cmd.Parameters.Add(Query.NewParameter("BPIDN1", BPIDN + "%"));
}
switch (BPEDY_TYPE)
{
case "1":
sb.Append(" AND (BPEDY IS NULL OR BPEDY >= @TODAY) ");
break;
case "2":
sb.Append(" AND (BPEDY < @TODAY) ");
break;
}
switch (BPDPT_TYPE)
{
case "1":
sb.AppendFormat(" AND BPDPT IN {0} ", PublicVariable.InnerDepartment);
break;
case "2":
sb.AppendFormat(" AND BPDPT NOT IN {0} ", PublicVariable.InnerDepartment);
break;
}
AppendRange(sb, cmd, "BPSDY", BPSDY1, BPSDY2);
AppendRange(sb, cmd, "BPEDY", BPEDY1, BPEDY2);
if (!IsManager(userId))
{
sb.Append(" AND BPENO NOT IN ('00001','00002','00003') ");
}
}
private void AppendRange(StringBuilder sb, DbCommand cmd, string field, string value1, string value2)
{
bool has1 = !string.IsNullOrEmpty(value1);
bool has2 = !string.IsNullOrEmpty(value2);
if (has1 && has2)
{
sb.AppendFormat(" AND {0} >= @{0}1 AND {0} <= @{0}2 ", field);
cmd.Parameters.Add(Query.NewParameter(field + "1", value1));
cmd.Parameters.Add(Query.NewParameter(field + "2", value2));
}
else if (has1)
{
sb.AppendFormat(" AND {0} LIKE @{0}1 ", field);
cmd.Parameters.Add(Query.NewParameter(field + "1", value1 + "%"));
}
else if (has2)
{
sb.AppendFormat(" AND {0} LIKE @{0}2 ", field);
cmd.Parameters.Add(Query.NewParameter(field + "2", value2 + "%"));
}
}
}