347 lines
11 KiB
C#
347 lines
11 KiB
C#
using System;
|
||
using System.Text;
|
||
using System.Diagnostics;
|
||
using System.Linq;
|
||
using Model;
|
||
|
||
public partial class test_asenumerable_check : System.Web.UI.Page
|
||
{
|
||
private StringBuilder output = new StringBuilder();
|
||
private int passCount = 0;
|
||
private int failCount = 0;
|
||
private int warnCount = 0;
|
||
|
||
protected void Page_Load(object sender, EventArgs e)
|
||
{
|
||
if (!IsPostBack)
|
||
{
|
||
litResult.Text = "<p style='color:#888;'>點擊「執行檢測」開始測試修改結果</p>";
|
||
}
|
||
}
|
||
|
||
protected void btnRunTest_Click(object sender, EventArgs e)
|
||
{
|
||
output.Clear();
|
||
passCount = 0;
|
||
failCount = 0;
|
||
warnCount = 0;
|
||
|
||
output.AppendLine("<div style='margin-bottom: 20px;'>");
|
||
output.AppendLine($"<p>測試時間: {DateTime.Now:yyyy-MM-dd HH:mm:ss}</p>");
|
||
output.AppendLine("</div>");
|
||
|
||
// 執行所有測試
|
||
TestAccountingKind();
|
||
TestActivityKind();
|
||
TestFollowers();
|
||
TestMembers();
|
||
TestOrders();
|
||
|
||
// 顯示總結
|
||
output.AppendLine("<hr />");
|
||
output.AppendLine("<h2>📊 測試總結</h2>");
|
||
output.AppendLine($"<p class='success'>✅ 通過: {passCount} 項</p>");
|
||
output.AppendLine($"<p class='error'>❌ 失敗: {failCount} 項</p>");
|
||
output.AppendLine($"<p class='warning'>⚠️ 警告: {warnCount} 項</p>");
|
||
|
||
if (failCount == 0)
|
||
{
|
||
output.AppendLine("<h3 class='success'>🎉 所有測試通過!修改成功!</h3>");
|
||
}
|
||
else
|
||
{
|
||
output.AppendLine("<h3 class='error'>⚠️ 發現問題,請檢查失敗的項目</h3>");
|
||
}
|
||
|
||
litResult.Text = output.ToString();
|
||
}
|
||
|
||
private void TestAccountingKind()
|
||
{
|
||
output.AppendLine("<h3>測試 1: accounting_kind 查詢優化</h3>");
|
||
|
||
using (var db = new ezEntities())
|
||
{
|
||
var sqlLog = new StringBuilder();
|
||
db.Database.Log = sql => sqlLog.AppendLine(sql);
|
||
|
||
try
|
||
{
|
||
// 測試 1.1: 單筆查詢
|
||
sqlLog.Clear();
|
||
var sw = Stopwatch.StartNew();
|
||
var result = db.accounting_kind.Where(q => q.num == 1).FirstOrDefault();
|
||
sw.Stop();
|
||
|
||
CheckQuery("單筆查詢 (Where + FirstOrDefault)",
|
||
sqlLog.ToString(),
|
||
sw.ElapsedMilliseconds,
|
||
shouldHaveWhere: true,
|
||
shouldHaveSelectAll: false,
|
||
maxTime: 50);
|
||
|
||
// 測試 1.2: 檢查子資料 (應該用 Any)
|
||
sqlLog.Clear();
|
||
sw.Restart();
|
||
var hasChildren = db.accounting_kind.Any(q => q.root == 1);
|
||
sw.Stop();
|
||
|
||
CheckQuery("檢查子資料存在 (Any)",
|
||
sqlLog.ToString(),
|
||
sw.ElapsedMilliseconds,
|
||
shouldHaveWhere: true,
|
||
shouldHaveExists: true,
|
||
maxTime: 30);
|
||
|
||
// 測試 1.3: 取得子資料清單
|
||
sqlLog.Clear();
|
||
sw.Restart();
|
||
var children = db.accounting_kind.Where(q => q.root == 1).ToList();
|
||
sw.Stop();
|
||
|
||
CheckQuery("取得子資料清單 (Where + ToList)",
|
||
sqlLog.ToString(),
|
||
sw.ElapsedMilliseconds,
|
||
shouldHaveWhere: true,
|
||
shouldHaveSelectAll: false,
|
||
maxTime: 100);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogError($"accounting_kind 測試失敗: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
private void TestActivityKind()
|
||
{
|
||
output.AppendLine("<h3>測試 2: activity_kind 查詢優化</h3>");
|
||
|
||
using (var db = new ezEntities())
|
||
{
|
||
var sqlLog = new StringBuilder();
|
||
db.Database.Log = sql => sqlLog.AppendLine(sql);
|
||
|
||
try
|
||
{
|
||
// 單筆查詢 + 排序
|
||
sqlLog.Clear();
|
||
var sw = Stopwatch.StartNew();
|
||
var result = db.activity_kind
|
||
.Where(q => q.num == 1)
|
||
.OrderBy(q => q.kind)
|
||
.FirstOrDefault();
|
||
sw.Stop();
|
||
|
||
CheckQuery("單筆查詢 + 排序 (Where + OrderBy + FirstOrDefault)",
|
||
sqlLog.ToString(),
|
||
sw.ElapsedMilliseconds,
|
||
shouldHaveWhere: true,
|
||
shouldHaveOrderBy: true,
|
||
maxTime: 50);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogError($"activity_kind 測試失敗: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
private void TestFollowers()
|
||
{
|
||
output.AppendLine("<h3>測試 3: followers 查詢優化</h3>");
|
||
|
||
using (var db = new ezEntities())
|
||
{
|
||
var sqlLog = new StringBuilder();
|
||
db.Database.Log = sql => sqlLog.AppendLine(sql);
|
||
|
||
try
|
||
{
|
||
// 測試字串查詢 (Contains)
|
||
sqlLog.Clear();
|
||
var sw = Stopwatch.StartNew();
|
||
var result = db.followers
|
||
.Where(q => q.f_number.Contains("A"))
|
||
.Take(10)
|
||
.ToList();
|
||
sw.Stop();
|
||
|
||
CheckQuery("字串查詢 (Contains)",
|
||
sqlLog.ToString(),
|
||
sw.ElapsedMilliseconds,
|
||
shouldHaveWhere: true,
|
||
shouldHaveLike: true,
|
||
maxTime: 100);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogError($"followers 測試失敗: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
private void TestMembers()
|
||
{
|
||
output.AppendLine("<h3>測試 4: members 查詢優化</h3>");
|
||
|
||
using (var db = new ezEntities())
|
||
{
|
||
var sqlLog = new StringBuilder();
|
||
db.Database.Log = sql => sqlLog.AppendLine(sql);
|
||
|
||
try
|
||
{
|
||
// 測試批次查詢
|
||
var ids = new[] { 1, 2, 3 };
|
||
sqlLog.Clear();
|
||
var sw = Stopwatch.StartNew();
|
||
var result = db.members.Where(q => ids.Contains(q.num)).ToList();
|
||
sw.Stop();
|
||
|
||
CheckQuery("批次 ID 查詢 (Contains)",
|
||
sqlLog.ToString(),
|
||
sw.ElapsedMilliseconds,
|
||
shouldHaveWhere: true,
|
||
shouldHaveIn: true,
|
||
maxTime: 100);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogError($"members 測試失敗: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
private void TestOrders()
|
||
{
|
||
output.AppendLine("<h3>測試 5: pro_order_detail 聚合查詢</h3>");
|
||
|
||
using (var db = new ezEntities())
|
||
{
|
||
var sqlLog = new StringBuilder();
|
||
db.Database.Log = sql => sqlLog.AppendLine(sql);
|
||
|
||
try
|
||
{
|
||
// 測試 Count
|
||
sqlLog.Clear();
|
||
var sw = Stopwatch.StartNew();
|
||
var count = db.pro_order_detail.Count(q => q.num > 0);
|
||
sw.Stop();
|
||
|
||
CheckQuery("Count 查詢",
|
||
sqlLog.ToString(),
|
||
sw.ElapsedMilliseconds,
|
||
shouldHaveWhere: true,
|
||
shouldHaveCount: true,
|
||
maxTime: 50);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogError($"pro_order_detail 測試失敗: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
private void CheckQuery(string testName, string sql, long milliseconds,
|
||
bool shouldHaveWhere = false,
|
||
bool shouldHaveSelectAll = false,
|
||
bool shouldHaveExists = false,
|
||
bool shouldHaveOrderBy = false,
|
||
bool shouldHaveLike = false,
|
||
bool shouldHaveIn = false,
|
||
bool shouldHaveCount = false,
|
||
long maxTime = 100)
|
||
{
|
||
output.AppendLine("<div class='test-item'>");
|
||
output.AppendLine($"<h4>🔸 {testName}</h4>");
|
||
output.AppendLine($"<p>執行時間: {milliseconds}ms</p>");
|
||
|
||
bool passed = true;
|
||
var issues = new StringBuilder();
|
||
|
||
// 檢查是否有 WHERE 條件
|
||
if (shouldHaveWhere && !sql.Contains("WHERE"))
|
||
{
|
||
issues.AppendLine("❌ 缺少 WHERE 條件(可能載入整表)<br/>");
|
||
passed = false;
|
||
}
|
||
|
||
// 檢查是否有不當的 SELECT *
|
||
if (!shouldHaveSelectAll && sql.Contains("SELECT") && !sql.Contains("WHERE") && !sql.Contains("TOP"))
|
||
{
|
||
issues.AppendLine("❌ SELECT 沒有條件限制(載入整表)<br/>");
|
||
passed = false;
|
||
}
|
||
|
||
// 檢查是否使用 EXISTS(Any 應該產生)
|
||
if (shouldHaveExists && !sql.Contains("EXISTS"))
|
||
{
|
||
issues.AppendLine("⚠️ 建議使用 EXISTS 而非載入資料<br/>");
|
||
warnCount++;
|
||
}
|
||
|
||
// 檢查是否有 ORDER BY
|
||
if (shouldHaveOrderBy && !sql.Contains("ORDER BY"))
|
||
{
|
||
issues.AppendLine("❌ 缺少 ORDER BY(排序應該在資料庫執行)<br/>");
|
||
passed = false;
|
||
}
|
||
|
||
// 檢查是否有 LIKE(Contains 應該產生)
|
||
if (shouldHaveLike && !sql.Contains("LIKE"))
|
||
{
|
||
issues.AppendLine("❌ 字串查詢未轉為 LIKE<br/>");
|
||
passed = false;
|
||
}
|
||
|
||
// 檢查是否有 IN(批次查詢應該產生)
|
||
if (shouldHaveIn && !sql.Contains("IN"))
|
||
{
|
||
issues.AppendLine("❌ 批次查詢未轉為 IN<br/>");
|
||
passed = false;
|
||
}
|
||
|
||
// 檢查是否有 COUNT(聚合函數應該在資料庫執行)
|
||
if (shouldHaveCount && !sql.Contains("COUNT"))
|
||
{
|
||
issues.AppendLine("❌ COUNT 未在資料庫執行<br/>");
|
||
passed = false;
|
||
}
|
||
|
||
// 檢查執行時間
|
||
if (milliseconds > maxTime)
|
||
{
|
||
issues.AppendLine($"⚠️ 執行時間較長 (>{maxTime}ms),可能仍有優化空間<br/>");
|
||
warnCount++;
|
||
}
|
||
|
||
if (passed)
|
||
{
|
||
output.AppendLine("<p class='success'>✅ 測試通過</p>");
|
||
passCount++;
|
||
}
|
||
else
|
||
{
|
||
output.AppendLine("<p class='error'>❌ 測試失敗</p>");
|
||
output.AppendLine($"<div style='color:#f48771;'>{issues}</div>");
|
||
failCount++;
|
||
}
|
||
|
||
// 顯示 SQL
|
||
output.AppendLine("<div class='sql-box'>");
|
||
output.AppendLine("<strong>產生的 SQL:</strong><br/>");
|
||
output.AppendLine($"<pre>{System.Web.HttpUtility.HtmlEncode(sql)}</pre>");
|
||
output.AppendLine("</div>");
|
||
output.AppendLine("</div>");
|
||
}
|
||
|
||
private void LogError(string message)
|
||
{
|
||
output.AppendLine($"<p class='error'>❌ {message}</p>");
|
||
failCount++;
|
||
}
|
||
}
|
||
|