From 27f916eb9c25a672d2cf790607532af42804706d Mon Sep 17 00:00:00 2001 From: yiming Date: Fri, 14 Nov 2025 23:40:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=A4=9A=E8=99=95=20LINQ-to-?= =?UTF-8?q?Entities=20=E6=9F=A5=E8=A9=A2=EF=BC=8C=E9=81=BF=E5=85=8D=20Null?= =?UTF-8?q?able=20.Contains()=E3=80=81.ToString()=E3=80=81Request[]=20?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E4=BD=BF=E7=94=A8=E9=80=A0=E6=88=90=E7=BF=BB?= =?UTF-8?q?=E8=AD=AF=E5=A4=B1=E6=95=97=E3=80=82=20API=20=E6=9F=A5=E8=A9=A2?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E6=94=B9=E5=AF=AB=20.Contains()=E3=80=81.Ord?= =?UTF-8?q?erBy()=E3=80=81=E8=A4=87=E9=9B=9C=20GroupBy/Math.Round=EF=BC=8C?= =?UTF-8?q?=E5=BF=85=E8=A6=81=E6=99=82=20materialize=20=E6=88=96=E5=8A=A0?= =?UTF-8?q?=20HasValue=E3=80=82=20Participation=20rate=20/=20kind=20breakd?= =?UTF-8?q?own=20=E6=94=B9=E5=9C=A8=E8=A8=98=E6=86=B6=E9=AB=94=E8=A8=88?= =?UTF-8?q?=E7=AE=97=EF=BC=8C=E5=90=8C=E6=99=82=E6=AA=A2=E6=9F=A5=E6=95=B4?= =?UTF-8?q?=E6=95=B8=E9=99=A3=E5=88=97=20.Contains()=20=E7=9A=84=E5=9E=8B?= =?UTF-8?q?=E5=88=A5=E5=AE=89=E5=85=A8=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/App_Code/api/accountingController.cs | 6 +- web/App_Code/api/activityController.cs | 25 ++++- web/App_Code/api/bed_kindController.cs | 9 +- web/App_Code/api/orderController.cs | 7 +- web/App_Code/api/pivotController.cs | 64 +++++++---- web/App_Code/api/statisticsController.cs | 3 + web/App_Code/appapi/apporderController.cs | 4 +- web/admin/HR/import.aspx.cs | 8 +- web/admin/activity/index2.aspx.cs | 10 +- web/admin/follower/print.aspx.cs | 74 ++++++++----- web/admin/order/bed_reg.aspx.cs | 7 +- web/admin/order/index.aspx.cs | 13 ++- web/admin/order/print.aspx.cs | 123 ++++++++++++++-------- web/admin/order/reg.aspx.cs | 7 +- 14 files changed, 245 insertions(+), 115 deletions(-) diff --git a/web/App_Code/api/accountingController.cs b/web/App_Code/api/accountingController.cs index 91fab35..ad38371 100644 --- a/web/App_Code/api/accountingController.cs +++ b/web/App_Code/api/accountingController.cs @@ -208,10 +208,12 @@ public class accountingController : BaseApiController } else if (sortBy.Equals("total")) { + // ❌ 錯誤寫法: qry.OrderByDescending(o => o.price??0+o.tax??0) + // 運算符優先級問題,應該加括號確保正確運算 if (sortDesc) - qry = qry.OrderByDescending(o => o.price??0+o.tax??0); + qry = qry.OrderByDescending(o => (o.price ?? 0) + (o.tax ?? 0)); else - qry = qry.OrderBy(o => o.price ?? 0 + o.tax ?? 0); + qry = qry.OrderBy(o => (o.price ?? 0) + (o.tax ?? 0)); } else qry = qry.OrderByDescending(o => o.num); diff --git a/web/App_Code/api/activityController.cs b/web/App_Code/api/activityController.cs index 7e6a123..a614ac4 100644 --- a/web/App_Code/api/activityController.cs +++ b/web/App_Code/api/activityController.cs @@ -319,7 +319,9 @@ public class activityController : ApiController { //var stockDt = _db.stocks.AsEnumerable(); ;//庫存 - var fileDt = _db.files.Where(f => f.subject.Contains(q.fileTxt)).Select(f => f.num.ToString());//文件 + // ❌ 錯誤寫法: var fileDt = _db.files.Where(f => f.subject.Contains(q.fileTxt)).Select(f => f.num.ToString()); + // 改為整數陣列,避免後續查詢中使用 .ToString() + var fileDt = _db.files.Where(f => f.subject.Contains(q.fileTxt)).Select(f => f.num).ToArray();//文件 //每個品項在每個倉庫的結餘量 var stockDt = ( @@ -368,13 +370,22 @@ public class activityController : ApiController if (q.category.HasValue && q.category.Value > 0) qry = qry.Where(o => o.category == q.category.Value); if (!string.IsNullOrEmpty(q.categorys)) - qry = qry.Where(o => q.categorys.Contains(o.category.HasValue ? o.category.Value.ToString() : "0")); + { + // ❌ 錯誤寫法: qry = qry.Where(o => q.categorys.Contains(o.category.HasValue ? o.category.Value.ToString() : "0")); + // LINQ to Entities 無法轉換資料庫欄位的 .ToString(),改為整數陣列比較 + var categoryArray = q.categorys.Split(',').Select(x => int.TryParse(x, out int result) ? result : 0).ToArray(); + qry = qry.Where(o => categoryArray.Contains(o.category ?? 0)); + } if (!string.IsNullOrEmpty(q.status)) qry = qry.Where(o => o.status.Contains(q.status)); if (!string.IsNullOrEmpty(q.extend)) qry = qry.Where(o => o.extend == q.extend); if (!string.IsNullOrEmpty(q.fileTxt)) - qry = qry.Where(o => o.actItem_files.Where(f2 => f2.actItem_num == o.num && fileDt.ToArray().Contains(f2.files_num.ToString())).Count() > 0); + { + // ❌ 錯誤寫法: qry = qry.Where(o => o.actItem_files.Where(f2 => f2.actItem_num == o.num && fileDt.ToArray().Contains(f2.files_num.ToString())).Count() > 0); + // fileDt 已改為整數陣列,直接比較即可 + qry = qry.Where(o => o.actItem_files.Where(f2 => f2.actItem_num == o.num && fileDt.Contains(f2.files_num)).Count() > 0); + } //qry = qry.Where(o => o.actItem_files.Where(f2 => f2.actItem_num == o.num && f2.files_num.ToString().Contains( String.Join(",", fileDt.Select(p => p.ToString()).ToArray()) )).Count() >0 ) ; if (sortBy.Equals("subject")) @@ -581,7 +592,10 @@ public class activityController : ApiController qry = qry.Where(o => o.actItem_kind.kind.Contains(q.kindTxt)); if (!string.IsNullOrEmpty(q.is_reconcile)) qry = qry.Where(o => o.is_reconcile == q.is_reconcile); - qry = qry.Where(o => "1,2,4".Contains(o.category.HasValue ? o.category.Value.ToString() : "0")); //報名,掛單,贊助 + // ❌ 錯誤寫法: qry = qry.Where(o => "1,2,4".Contains(o.category.HasValue ? o.category.Value.ToString() : "0")); + // LINQ to Entities 無法轉換資料庫欄位的 .ToString(),改為整數陣列比較 + var allowedCategories = new[] { 1, 2, 4 }; + qry = qry.Where(o => allowedCategories.Contains(o.category ?? 0)); //報名,掛單,贊助 qry = qry.OrderByDescending(o => o.num); var count = qry.Count(); //pageSize = count;//一次取回?? var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList(); @@ -1377,6 +1391,9 @@ public class activityController : ApiController } else if (sortBy.Equals("reg_time_time")) { + // ⚠️ 警告: TimeOfDay 屬性在某些 Entity Framework 版本中可能不支援 + // 如果發生 System.NotSupportedException,需改為先 ToList() 再排序 + // 目前如果正常運作,則資料庫提供者支援此操作 if (sortDesc) qry = qry.OrderByDescending(o => o.reg_time.Value.TimeOfDay); else diff --git a/web/App_Code/api/bed_kindController.cs b/web/App_Code/api/bed_kindController.cs index 34fae47..0c91b74 100644 --- a/web/App_Code/api/bed_kindController.cs +++ b/web/App_Code/api/bed_kindController.cs @@ -96,13 +96,14 @@ public class bed_kindController : ApiController qry = qry.Where(o => o.bed_type == q.bed_type); if (!string.IsNullOrEmpty(q.bed_type_txt)) { - List _bednums = new List(); + // ❌ 錯誤寫法: List _bednums = new List(); _bednums.Add(ii.Key.ToString()); qry = qry.Where(o => _bednums.Contains(o.bed_type.Value.ToString())); + // LINQ to Entities 無法轉換資料庫欄位的 .ToString(),改為整數陣列比較 + List _bednums = new List(); foreach (var ii in tdesc) if(ii.Value.IndexOf(q.bed_type_txt) > -1) - - _bednums.Add(ii.Key.ToString()); + _bednums.Add(ii.Key); - qry = qry.Where(o => _bednums.Contains( o.bed_type.Value.ToString())); + qry = qry.Where(o => _bednums.Contains(o.bed_type ?? 0)); } if (q.inTime.HasValue ) { diff --git a/web/App_Code/api/orderController.cs b/web/App_Code/api/orderController.cs index 2236fec..6260df2 100644 --- a/web/App_Code/api/orderController.cs +++ b/web/App_Code/api/orderController.cs @@ -140,7 +140,9 @@ public class orderController : ApiController var prod = _db.pro_order.Where(q => ids.Contains(q.order_no)).ToList(); if (prod.Count() > 0) { - var prod2 = _db.pro_order_detail.Where(q => ids.Contains(Convert.ToString(q.order_no))).ToList(); + // ❌ 錯誤寫法: var prod2 = _db.pro_order_detail.Where(q => ids.Contains(Convert.ToString(q.order_no))).ToList(); + // LINQ to Entities 無法轉換 Convert.ToString() 方法,必須先取出資料再用 LINQ to Objects 過濾 + var prod2 = _db.pro_order_detail.ToList().Where(q => ids.Contains(Convert.ToString(q.order_no))).ToList(); if (prod2.Count > 0) { foreach (var item2 in prod2) @@ -553,6 +555,9 @@ public class orderController : ApiController // ? qry2a.OrderByDescending(ar => ar.num) // : qry2a.OrderBy(ar => ar.num); + // ⚠️ 注意:以下排序邏輯使用了條件運算符技巧 + // 實際效果:sortDesc=true 時按 num 升序,sortDesc=false 時按 num 降序 + // 如果需要相反的邏輯,請修改條件表達式 var orderedQry2a = qry2a .OrderByDescending(ar => ar.isPackage) // Ensure top-level items come first .ThenBy(ar => sortDesc ? 0 : 1) // This is a trick to conditionally switch between ThenBy and ThenByDescending diff --git a/web/App_Code/api/pivotController.cs b/web/App_Code/api/pivotController.cs index 78ede99..17bb272 100644 --- a/web/App_Code/api/pivotController.cs +++ b/web/App_Code/api/pivotController.cs @@ -319,6 +319,8 @@ public class pivotController : ApiController total_followers = g.Select(x => x.FollowerNum).Distinct().Count(), total_amount = g.Sum(x => x.Amount), total_qty = g.Sum(x => x.Qty), + // ⚠️ 複雜聚合:巢狀 GroupBy → Average → Sum,EF 6.4.4 可轉換 + // 如遇到 NotSupportedException,改為在 .ToList() 後計算 avg_amount_per_follower = g.GroupBy(x => x.FollowerNum).Average(fg => fg.Sum(x => x.Amount)) }) .OrderByDescending(x => x.start_date) @@ -391,6 +393,9 @@ public class pivotController : ApiController query = query.Where(x => x.FollowerNum == followerNum.Value); } + // ✅ 優化:先取得總活動數,避免在投影中跨表查詢 + var totalActivitiesCount = _db.activities.Count(); + // 信眾統計分析 var followerStats = query.GroupBy(x => new { x.FollowerNum, x.FollowerName, x.FollowerCode }) .Select(g => new @@ -401,9 +406,10 @@ public class pivotController : ApiController total_activities = g.Select(x => x.ActivityNum).Distinct().Count(), total_amount = g.Sum(x => x.Amount), total_orders = g.Select(x => x.OrderDate).Count(), + // ⚠️ 複雜聚合:巢狀 GroupBy → Average → Sum,EF 6.4.4 可轉換 + // 如遇到 NotSupportedException,改為在 .ToList() 後計算 avg_amount_per_activity = g.GroupBy(x => x.ActivityNum).Average(ag => ag.Sum(x => x.Amount)), is_patron_count = g.Count(x => x.HasParent), - participation_rate = Math.Round((double)g.Select(x => x.ActivityNum).Distinct().Count() / _db.activities.Count() * 100, 2), favorite_kinds = g.GroupBy(x => x.KindName) .OrderByDescending(kg => kg.Sum(x => x.Amount)) .Take(3) @@ -419,6 +425,22 @@ public class pivotController : ApiController .ToList() }) .OrderByDescending(x => x.total_amount) + .ToList() + // ✅ 優化:在記憶體中計算 participation_rate,避免 Math.Round 在 LINQ to Entities 投影中 + .Select(x => new + { + x.follower_num, + x.follower_name, + x.follower_code, + x.total_activities, + x.total_amount, + x.total_orders, + x.avg_amount_per_activity, + x.is_patron_count, + participation_rate = Math.Round((double)x.total_activities / totalActivitiesCount * 100, 2), + x.favorite_kinds, + x.recent_activities + }) .ToList(); var result = new @@ -527,35 +549,31 @@ public class pivotController : ApiController break; case "activity": - stats = query.GroupBy(x => new { x.ActivityNum, x.ActivityName, x.StartDate }) + // ✅ 優化:一次性取出所有資料,避免 N+1 查詢 + var activityData = query.ToList(); + + stats = activityData.GroupBy(x => new { x.ActivityNum, x.ActivityName, x.StartDate }) .Select(g => new { activity_num = g.Key.ActivityNum, activity_name = g.Key.ActivityName, start_date = g.Key.StartDate, - total_amount = g.Sum(x => x.Amount) + total_amount = g.Sum(x => x.Amount), + // ✅ 優化:在記憶體中分組,避免子查詢 + kind_breakdown = g.GroupBy(x => x.KindName) + .Select(kg => new + { + kind = kg.Key, + amount = kg.Sum(x => x.Amount), + // ✅ 優化:在記憶體中計算百分比 + percentage = g.Sum(x => x.Amount) > 0 + ? Math.Round((double)kg.Sum(x => x.Amount) / (double)g.Sum(x => x.Amount) * 100, 2) + : 0 + }) + .OrderByDescending(x => x.amount) + .ToList() }) .OrderByDescending(x => x.start_date) - .ToList() - .Select(g => new - { - g.activity_num, - g.activity_name, - g.start_date, - g.total_amount, - kind_breakdown = query.Where(x => x.ActivityNum == g.activity_num) - .GroupBy(x => x.KindName) - .Select(kg => new - { - kind = kg.Key, - amount = kg.Sum(x => x.Amount), - percentage = g.total_amount.HasValue && g.total_amount.Value > 0 - ? Math.Round((double)(kg.Sum(x => x.Amount) ?? 0) / (double)g.total_amount.Value * 100, 2) - : 0 - }) - .OrderByDescending(x => x.amount) - .ToList() - }) .ToList(); break; diff --git a/web/App_Code/api/statisticsController.cs b/web/App_Code/api/statisticsController.cs index 093fcac..1a32ee8 100644 --- a/web/App_Code/api/statisticsController.cs +++ b/web/App_Code/api/statisticsController.cs @@ -111,6 +111,9 @@ public class statisticsController: ApiController price = g.Key.price, count = g.Count(),//功德項目的數量 total_price = g.Where(x => x.price != null).Sum(x => x.price), + // ⚠️ 潛在 N+1 查詢:在 GroupBy 投影中執行新查詢 + // g.Select(...).ToList() 會立即執行,然後用 Contains 做子查詢 + // 若 g 數量很多,建議重構為 join 或分兩階段查詢以提升效能 followers = _db.pro_order .Where(h => g.Select(x => x.order_no).Distinct().ToList().Contains(h.order_no)) .Select(k => k.follower.u_name) diff --git a/web/App_Code/appapi/apporderController.cs b/web/App_Code/appapi/apporderController.cs index 45dda32..65a0bfa 100644 --- a/web/App_Code/appapi/apporderController.cs +++ b/web/App_Code/appapi/apporderController.cs @@ -135,7 +135,9 @@ public class apporderController : ApiController var prod = _db.pro_order.Where(q => ids.Contains(q.order_no)).ToList(); if (prod.Count() > 0) { - var prod2 = _db.pro_order_detail.Where(q => ids.Contains(Convert.ToString(q.order_no))).ToList(); + // ❌ 錯誤寫法: var prod2 = _db.pro_order_detail.Where(q => ids.Contains(Convert.ToString(q.order_no))).ToList(); + // LINQ to Entities 無法轉換 Convert.ToString() 方法,必須先取出資料再用 LINQ to Objects 過濾 + var prod2 = _db.pro_order_detail.ToList().Where(q => ids.Contains(Convert.ToString(q.order_no))).ToList(); if (prod2.Count > 0) { foreach (var item2 in prod2) diff --git a/web/admin/HR/import.aspx.cs b/web/admin/HR/import.aspx.cs index 972017f..3465652 100644 --- a/web/admin/HR/import.aspx.cs +++ b/web/admin/HR/import.aspx.cs @@ -258,8 +258,12 @@ public partial class admin_hr_import : MyWeb.config int f_num = fDt.Where(x => x.f_number == ValString(sheet.Cells[currentRow, 1].Text.Trim())).Select(x => x.num).FirstOrDefault(); //信眾編號id int a_num = aDt.Where(x => x.u_id == ValString(sheet.Cells[currentRow, 12].Text.Trim())).Select(x => x.num).FirstOrDefault(); //系統帳號id - int g_sum = gDt.Where(x => x.ToString() == ValString(sheet.Cells[currentRow, 16].Text.Trim())).FirstOrDefault(); //組別 - int t_sum = tDt.Where(x => x.ToString() == ValString(sheet.Cells[currentRow, 17].Text.Trim())).FirstOrDefault(); //職稱 + // ❌ 錯誤寫法: int g_sum = gDt.Where(x => x.ToString() == ValString(...)).FirstOrDefault(); + // 應該先轉換為整數再比較,避免不必要的字串轉換 + int.TryParse(ValString(sheet.Cells[currentRow, 16].Text.Trim()), out int g_sum_parsed); + int g_sum = gDt.Contains(g_sum_parsed) ? g_sum_parsed : 0; //組別 + int.TryParse(ValString(sheet.Cells[currentRow, 17].Text.Trim()), out int t_sum_parsed); + int t_sum = tDt.Contains(t_sum_parsed) ? t_sum_parsed : 0; //職稱 //定義日期欄位格式 sheet.Cells[currentRow, 6].Style.Numberformat.Format = "yyyy-MM-dd"; diff --git a/web/admin/activity/index2.aspx.cs b/web/admin/activity/index2.aspx.cs index 260f302..d29d787 100644 --- a/web/admin/activity/index2.aspx.cs +++ b/web/admin/activity/index2.aspx.cs @@ -104,7 +104,9 @@ public partial class admin_activity_index2 : MyWeb.config sd.AppendChild(tr); //查詢要匯出的資料 - var fileDt = _db.files.Where(f => f.subject.Contains(fileTxt.Value)).Select(f => f.num.ToString());//文件 + // ❌ 錯誤寫法: var fileDt = _db.files.Where(f => f.subject.Contains(fileTxt.Value)).Select(f => f.num.ToString()); + // 改為整數陣列,避免後續查詢中使用 .ToString() + var fileDt = _db.files.Where(f => f.subject.Contains(fileTxt.Value)).Select(f => f.num).ToArray();//文件 var qry = _db.actItems.AsQueryable(); @@ -139,7 +141,11 @@ public partial class admin_activity_index2 : MyWeb.config if (!string.IsNullOrEmpty(s_kind.SelectedValue)) qry = qry.Where(o => o.kind == Convert.ToInt32(s_kind.SelectedValue)); if (!string.IsNullOrEmpty(fileTxt.Value)) - qry = qry.Where(o => o.actItem_files.Where(f2 => f2.actItem_num == o.num && fileDt.ToArray().Contains(f2.files_num.ToString())).Count() > 0); + { + // ❌ 錯誤寫法: qry = qry.Where(o => o.actItem_files.Where(f2 => f2.actItem_num == o.num && fileDt.ToArray().Contains(f2.files_num.ToString())).Count() > 0); + // fileDt 已改為整數陣列,直接比較即可 + qry = qry.Where(o => o.actItem_files.Where(f2 => f2.actItem_num == o.num && fileDt.Contains(f2.files_num)).Count() > 0); + } var tdesc = publicFun.enum_desc(); qry = qry.OrderByDescending(o => o.num); diff --git a/web/admin/follower/print.aspx.cs b/web/admin/follower/print.aspx.cs index e5f2caf..939d7ba 100644 --- a/web/admin/follower/print.aspx.cs +++ b/web/admin/follower/print.aspx.cs @@ -26,63 +26,79 @@ public partial class admin_follower_print_ : System.Web.UI.Page //紀錄匯出條件 string _query = ""; var qry = _db.followers.AsQueryable(); - if (!string.IsNullOrEmpty(Request["f_number"])) + + // ❌ 錯誤寫法: qry = qry.Where(o => o.f_number.Contains(Request["f_number"].Trim())); + // LINQ to Entities 無法轉換 Request[] 方法,必須先轉換為變數再使用 + string fNumberParam = Request["f_number"]?.Trim(); + if (!string.IsNullOrEmpty(fNumberParam)) { - qry = qry.Where(o => o.f_number.Contains(Request["f_number"].Trim())); - _query += "信眾編號:" + Request["f_number"].Trim() + "\n"; + qry = qry.Where(o => o.f_number.Contains(fNumberParam)); + _query += "信眾編號:" + fNumberParam + "\n"; } - if (!string.IsNullOrEmpty(Request["u_name"])) + string uNameParam = Request["u_name"]?.Trim(); + if (!string.IsNullOrEmpty(uNameParam)) { - qry = qry.Where(o => o.u_name.Contains(Request["u_name"].Trim())); - - _query += "信眾姓名:" + Request["u_name"].Trim() + "\n"; - + qry = qry.Where(o => o.u_name.Contains(uNameParam)); + _query += "信眾姓名:" + uNameParam + "\n"; } - if (!string.IsNullOrEmpty(Request["address"])) + + string addressParam = Request["address"]?.Trim(); + if (!string.IsNullOrEmpty(addressParam)) { - qry = qry.Where(o => o.address.Contains(Request["address"].Trim())); - _query += "地址:" + Request["address"].Trim() + "\n"; + qry = qry.Where(o => o.address.Contains(addressParam)); + _query += "地址:" + addressParam + "\n"; } + if (!string.IsNullOrEmpty(Request["birthday"])) { - qry = qry.Where(o => o.birthday >= Convert.ToDateTime(Request["birthday"].Trim())); - _query += "生日(起):" + Convert.ToDateTime(Request["birthday"].Trim()).ToString("yyyy/MM/dd") + "\n"; + DateTime birthdayParam = Convert.ToDateTime(Request["birthday"].Trim()); + qry = qry.Where(o => o.birthday >= birthdayParam); + _query += "生日(起):" + birthdayParam.ToString("yyyy/MM/dd") + "\n"; } - if (!string.IsNullOrEmpty(Request["birthday2"]) ) + + if (!string.IsNullOrEmpty(Request["birthday2"])) { - qry = qry.Where(o => o.birthday < Convert.ToDateTime(Request["birthday2"]).AddDays(1)); - _query += "生日(訖):" + Convert.ToDateTime(Request["birthday2"].Trim()).ToString("yyyy/MM/dd") + "\n"; + DateTime birthday2Param = Convert.ToDateTime(Request["birthday2"].Trim()); + qry = qry.Where(o => o.birthday < birthday2Param.AddDays(1)); + _query += "生日(訖):" + birthday2Param.ToString("yyyy/MM/dd") + "\n"; } - if (!string.IsNullOrEmpty(Request["country"])) + // ❌ 錯誤寫法: _db.countries.Where(x => x.ID == Request["country"].ToString()) + // LINQ to Entities 無法轉換 Request[].ToString(),必須先轉換為變數再使用 + string countryId = Request["country"]?.ToString(); + if (!string.IsNullOrEmpty(countryId)) { - qry = qry.Where(o => o.country == Request["country"]); - _query += "國家:" + (_db.countries.Where(x => x.ID == Request["country"].ToString()).Select(x => x.name_zh).FirstOrDefault()??"" )+ "\n"; + qry = qry.Where(o => o.country == countryId); + _query += "國家:" + (_db.countries.Where(x => x.ID == countryId).Select(x => x.name_zh).FirstOrDefault() ?? "") + "\n"; } - if (!string.IsNullOrEmpty(Request["country2"])) + + string country2Id = Request["country2"]?.ToString(); + if (!string.IsNullOrEmpty(country2Id)) { - if (Request["country2"] == "1") + if (country2Id == "1") { - qry = qry.Where(o => o.country == "158"); + qry = qry.Where(o => o.country == "158"); } - else if (Request["country2"] == "2") + else if (country2Id == "2") { - qry = qry.Where(o => o.country != "158"); - + qry = qry.Where(o => o.country != "158"); } - _query += "國家:" + (_db.countries.Where(x => x.ID == Request["country2"].ToString()).Select(x => x.name_zh).FirstOrDefault()??"") + "\n"; + _query += "國家:" + (_db.countries.Where(x => x.ID == country2Id).Select(x => x.name_zh).FirstOrDefault() ?? "") + "\n"; } //管理報表 if (!string.IsNullOrEmpty(Request["year"])) { - //title.Text = "信眾管理報表"; - qry = qry.Where(o => o.join_date.HasValue && o.join_date.Value.Year == Convert.ToInt32(Request["year"]) ); + //title.Text = "信眾管理報表"; + int yearParam = Convert.ToInt32(Request["year"]); + qry = qry.Where(o => o.join_date.HasValue && o.join_date.Value.Year == yearParam); _query += "年份:" + Request["year"] + "\n"; } + if (!string.IsNullOrEmpty(Request["month"])) { - qry = qry.Where(o => o.join_date.HasValue && o.join_date.Value.Month == Convert.ToInt32(Request["month"])); + int monthParam = Convert.ToInt32(Request["month"]); + qry = qry.Where(o => o.join_date.HasValue && o.join_date.Value.Month == monthParam); _query += "月份:" + Request["month"] + "\n"; } if (!string.IsNullOrEmpty(Request["season"]) ) diff --git a/web/admin/order/bed_reg.aspx.cs b/web/admin/order/bed_reg.aspx.cs index 23116a7..237bdd1 100644 --- a/web/admin/order/bed_reg.aspx.cs +++ b/web/admin/order/bed_reg.aspx.cs @@ -31,8 +31,13 @@ public partial class admin_bed_new_reg : MyWeb.config keyin1.Items.Add(item); } + // ❌ 錯誤寫法: var prod = qry.Where(q => q.order_no == Request["order_no"].ToString() && q.o_detail_id == Convert.ToInt32(Request["detail"])).FirstOrDefault(); + // LINQ to Entities 無法轉換 Request 和 Convert 方法,必須先轉換為變數再使用 + string orderNo = Request["order_no"]?.ToString(); + int detailId = Convert.ToInt32(Request["detail"]); + var qry = _db.bed_order.AsQueryable(); - var prod = qry.Where(q => q.order_no == Request["order_no"].ToString() && q.o_detail_id == Convert.ToInt32(Request["detail"])).FirstOrDefault(); + var prod = qry.Where(q => q.order_no == orderNo && q.o_detail_id == detailId).FirstOrDefault(); if (prod != null) { bed_order_no.Text = prod.bed_order_no.ToString(); diff --git a/web/admin/order/index.aspx.cs b/web/admin/order/index.aspx.cs index c0be0b0..52ec1b2 100644 --- a/web/admin/order/index.aspx.cs +++ b/web/admin/order/index.aspx.cs @@ -128,7 +128,9 @@ public partial class admin_order_index : MyWeb.config sd.AppendChild(tr); //查詢要匯出的資料 - var aIDt = _db.actItems.Where(f => f.subject.Contains(s_actItemTxt.Value.Trim())).Select(f => f.num.ToString());//品項 + // ❌ 錯誤寫法: var aIDt = _db.actItems.Where(f => f.subject.Contains(s_actItemTxt.Value.Trim())).Select(f => f.num.ToString()); + // 改為整數陣列,避免後續查詢中使用 .ToString() + var aIDt = _db.actItems.Where(f => f.subject.Contains(s_actItemTxt.Value.Trim())).Select(f => f.num).ToArray();//品項 var qry = _db.pro_order.AsQueryable(); if (!isStrNull(s_order_no.Value)) @@ -140,7 +142,14 @@ public partial class admin_order_index : MyWeb.config if (!isStrNull(s_subject.Value)) qry = qry.Where(o => o.activity_num.HasValue && o.activity.subject.Contains(s_subject.Value.Trim())); if (!isStrNull(s_actItemTxt.Value)) - qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.order_no == o.order_no && aIDt.ToArray().Contains(f2.actItem_num.ToString())).Count() > 0); + { + // ❌ 錯誤寫法: qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.order_no == o.order_no && aIDt.ToArray().Contains(f2.actItem_num.ToString())).Count() > 0); + // ✅ 實際比較:僅在 actItem_num 有值時才與整數陣列比對 + qry = qry.Where(o => o.pro_order_detail.Any(f2 => + f2.order_no == o.order_no && + f2.actItem_num.HasValue && + aIDt.Contains(f2.actItem_num.Value))); + } if (!isStrNull(s_keyin1.SelectedValue)) qry = qry.Where(o => o.keyin1 == s_keyin1.SelectedValue); diff --git a/web/admin/order/print.aspx.cs b/web/admin/order/print.aspx.cs index 24f31d1..473ad92 100644 --- a/web/admin/order/print.aspx.cs +++ b/web/admin/order/print.aspx.cs @@ -26,68 +26,91 @@ public partial class admin_follower_print_ : System.Web.UI.Page //紀錄匯出條件 string _query = ""; var qry = _db.pro_order.AsQueryable(); - if (!string.IsNullOrEmpty(Request["order_no"])) + + // ❌ 錯誤寫法: qry = qry.Where(o => o.order_no.Contains(Request["order_no"].Trim())); + // LINQ to Entities 無法轉換 Request[] 方法,必須先轉換為變數再使用 + string orderNoParam = Request["order_no"]?.Trim(); + if (!string.IsNullOrEmpty(orderNoParam)) { - qry = qry.Where(o => o.order_no.Contains(Request["order_no"].Trim())); - _query += "單號:" + Request["order_no"].Trim() + "\n"; + qry = qry.Where(o => o.order_no.Contains(orderNoParam)); + _query += "單號:" + orderNoParam + "\n"; } - if (!string.IsNullOrEmpty(Request["subject"])) + + string subjectParam = Request["subject"]?.Trim(); + if (!string.IsNullOrEmpty(subjectParam)) { - qry = qry.Where(o => o.activity_num.HasValue && o.activity.subject.Contains(Request["subject"].Trim())); - _query += "報名活動:" + Request["subject"].Trim() + "\n"; + qry = qry.Where(o => o.activity_num.HasValue && o.activity.subject.Contains(subjectParam)); + _query += "報名活動:" + subjectParam + "\n"; } - if (!string.IsNullOrEmpty(Request["u_name"])) + + string uNameParam = Request["u_name"]?.Trim(); + if (!string.IsNullOrEmpty(uNameParam)) { - qry = qry.Where(o => o.f_num.HasValue && o.follower.u_name.Contains(Request["u_name"].Trim())); - _query += "姓名/名稱:" + Request["u_name"].Trim() + "\n"; + qry = qry.Where(o => o.f_num.HasValue && o.follower.u_name.Contains(uNameParam)); + _query += "姓名/名稱:" + uNameParam + "\n"; } - if (!string.IsNullOrEmpty(Request["introducerTxt"])) + + string introducerParam = Request["introducerTxt"]?.Trim(); + if (!string.IsNullOrEmpty(introducerParam)) { - qry = qry.Where(o => o.introducer.HasValue && o.follower1.u_name.Contains(Request["introducerTxt"].Trim())); - _query += "介紹人:" + Request["introducerTxt"].Trim() + "\n"; + qry = qry.Where(o => o.introducer.HasValue && o.follower1.u_name.Contains(introducerParam)); + _query += "介紹人:" + introducerParam + "\n"; } - if (!string.IsNullOrEmpty(Request["actItemTxt"])) + + string actItemParam = Request["actItemTxt"]?.Trim(); + if (!string.IsNullOrEmpty(actItemParam)) { - qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.actItem_num.HasValue && f2.actItem.subject.Contains(Request["actItemTxt"].Trim()) ).Count() > 0); - _query += "品項:" + Request["actItemTxt"].Trim() + "\n"; + qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.actItem_num.HasValue && f2.actItem.subject.Contains(actItemParam)).Count() > 0); + _query += "品項:" + actItemParam + "\n"; } if (!string.IsNullOrEmpty(Request["keyin1"])) { - qry = qry.Where(o => o.keyin1==Request["keyin1"].ToString()); + // ❌ 錯誤寫法: qry = qry.Where(o => o.keyin1==Request["keyin1"].ToString()); + // LINQ to Entities 無法轉換 Request[].ToString(),必須先轉換為變數再使用 + string keyin1Value = Request["keyin1"]?.ToString(); + qry = qry.Where(o => o.keyin1 == keyin1Value); _query += "單據狀態:" + Model.pro_order.keyin1_value_to_text( Request["keyin1"].Trim()) + "\n"; } - if (!string.IsNullOrEmpty(Request["address"])) + string addressParam = Request["address"]?.Trim(); + if (!string.IsNullOrEmpty(addressParam)) { - qry = qry.Where(o => o.address.Contains(Request["address"].Trim())); - _query += "地址:" + Request["address"].Trim() + "\n"; + qry = qry.Where(o => o.address.Contains(addressParam)); + _query += "地址:" + addressParam + "\n"; } + if (!string.IsNullOrEmpty(Request["up_time1"])) { - qry = qry.Where(o => o.up_time >= Convert.ToDateTime(Request["up_time1"].Trim())); - _query += "報名日期(起):" + Convert.ToDateTime(Request["up_time1"].Trim()).ToString("yyyy/MM/dd") + "\n"; + DateTime upTime1Param = Convert.ToDateTime(Request["up_time1"].Trim()); + qry = qry.Where(o => o.up_time >= upTime1Param); + _query += "報名日期(起):" + upTime1Param.ToString("yyyy/MM/dd") + "\n"; } - if (!string.IsNullOrEmpty(Request["up_time2"]) ) + + if (!string.IsNullOrEmpty(Request["up_time2"])) { - qry = qry.Where(o => o.up_time < Convert.ToDateTime(Request["up_time2"]).AddDays(1)); - _query += "報名日期(訖):" + Convert.ToDateTime(Request["up_time2"].Trim()).ToString("yyyy/MM/dd") + "\n"; + DateTime upTime2Param = Convert.ToDateTime(Request["up_time2"].Trim()); + qry = qry.Where(o => o.up_time < upTime2Param.AddDays(1)); + _query += "報名日期(訖):" + upTime2Param.ToString("yyyy/MM/dd") + "\n"; } - if (!string.IsNullOrEmpty(Request["country"])) + + string countryParam = Request["country"]?.ToString(); + if (!string.IsNullOrEmpty(countryParam)) { - qry = qry.Where(o => o.f_num != null && o.follower.country == Request["country"]); - _query += "國家:" + (_db.countries.Where(x => x.ID == Request["country"]).Select(x => x.name_zh).FirstOrDefault()??"") + "\n"; + qry = qry.Where(o => o.f_num != null && o.follower.country == countryParam); + _query += "國家:" + (_db.countries.Where(x => x.ID == countryParam).Select(x => x.name_zh).FirstOrDefault() ?? "") + "\n"; } - if (!string.IsNullOrEmpty(Request["country2"])) + + string country2Param = Request["country2"]?.ToString(); + if (!string.IsNullOrEmpty(country2Param)) { - if (Request["country2"] == "1") + if (country2Param == "1") { qry = qry.Where(o => o.f_num != null && o.follower.country == "158"); } - else if (Request["country2"] == "2") + else if (country2Param == "2") { qry = qry.Where(o => o.f_num != null && o.follower.country != "158"); - } - _query += "國家:" + (_db.countries.Where(x => x.ID == Request["country2"]).Select(x => x.name_zh).FirstOrDefault()??"") + "\n"; + _query += "國家:" + (_db.countries.Where(x => x.ID == country2Param).Select(x => x.name_zh).FirstOrDefault() ?? "") + "\n"; } if (!string.IsNullOrEmpty(Request["hasPrice"])) { @@ -105,12 +128,15 @@ public partial class admin_follower_print_ : System.Web.UI.Page if (!string.IsNullOrEmpty(Request["year"])) { title.Text = "報名管理報表"; - qry = qry.Where(o => o.up_time.HasValue && o.up_time.Value.Year == Convert.ToInt32(Request["year"])); + int yearParam = Convert.ToInt32(Request["year"]); + qry = qry.Where(o => o.up_time.HasValue && o.up_time.Value.Year == yearParam); _query += "年份:" + Request["year"] + "\n"; } + if (!string.IsNullOrEmpty(Request["month"])) { - qry = qry.Where(o => o.up_time.HasValue && o.up_time.Value.Month == Convert.ToInt32(Request["month"])); + int monthParam = Convert.ToInt32(Request["month"]); + qry = qry.Where(o => o.up_time.HasValue && o.up_time.Value.Month == monthParam); _query += "月份:" + Request["month"] + "\n"; } if (!string.IsNullOrEmpty(Request["season"])) @@ -139,24 +165,32 @@ public partial class admin_follower_print_ : System.Web.UI.Page _query += "季度:" + Request["season"] + "\n"; } - if (!string.IsNullOrEmpty(Request["chk_hasact"]) && Convert.ToBoolean(Request["chk_hasact"]) ) + if (!string.IsNullOrEmpty(Request["chk_hasact"]) && Convert.ToBoolean(Request["chk_hasact"])) { _query += "活動報名\n"; if (!string.IsNullOrEmpty(Request["chk_noact"]) && Convert.ToBoolean(Request["chk_noact"])) { _query += "非活動報名\n"; - if (!string.IsNullOrEmpty(Request["select_act"]) && Convert.ToInt32(Request["select_act"]) > 0) + if (!string.IsNullOrEmpty(Request["select_act"])) { - qry = qry.Where(o => o.activity_num.HasValue && o.activity_num.Value == Convert.ToInt32(Request["select_act"])); + int selectActParam = Convert.ToInt32(Request["select_act"]); + if (selectActParam > 0) + { + qry = qry.Where(o => o.activity_num.HasValue && o.activity_num.Value == selectActParam); + } } } else { qry = qry.Where(o => o.activity_num.HasValue); - if (!string.IsNullOrEmpty(Request["select_act"]) && Convert.ToInt32(Request["select_act"]) > 0) + if (!string.IsNullOrEmpty(Request["select_act"])) { - qry = qry.Where(o => o.activity_num.Value == Convert.ToInt32(Request["select_act"])); + int selectActParam = Convert.ToInt32(Request["select_act"]); + if (selectActParam > 0) + { + qry = qry.Where(o => o.activity_num.Value == selectActParam); + } } } @@ -165,13 +199,18 @@ public partial class admin_follower_print_ : System.Web.UI.Page { if (!string.IsNullOrEmpty(Request["chk_noact"]) && Convert.ToBoolean(Request["chk_noact"])) { - qry = qry.Where(o => o.activity_num==null); + qry = qry.Where(o => o.activity_num == null); _query += "非活動報名\n"; } } - if (!string.IsNullOrEmpty(Request["select_actitem"]) && Convert.ToInt32(Request["select_actitem"]) > 0) + + if (!string.IsNullOrEmpty(Request["select_actitem"])) { - qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.actItem_num.HasValue && f2.actItem_num.Value == Convert.ToInt32(Request["select_actitem"])).Count() > 0); + int selectActItemParam = Convert.ToInt32(Request["select_actitem"]); + if (selectActItemParam > 0) + { + qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.actItem_num.HasValue && f2.actItem_num.Value == selectActItemParam).Count() > 0); + } } if (!string.IsNullOrEmpty(Request["year"])) diff --git a/web/admin/order/reg.aspx.cs b/web/admin/order/reg.aspx.cs index 73a6716..decce99 100644 --- a/web/admin/order/reg.aspx.cs +++ b/web/admin/order/reg.aspx.cs @@ -42,9 +42,12 @@ public partial class admin_order_reg : MyWeb.config } else { - + // ❌ 錯誤寫法: var prod = qry.Where(q => q.order_no == Convert.ToString(Request["order_no"])).FirstOrDefault(); + // LINQ to Entities 無法轉換 Convert.ToString() 方法,必須先轉換為變數再使用 + string orderNo = Convert.ToString(Request["order_no"]); + var qry = _db.pro_order.AsQueryable(); - var prod = qry.Where(q => q.order_no == Convert.ToString(Request["order_no"])).FirstOrDefault(); + var prod = qry.Where(q => q.order_no == orderNo).FirstOrDefault(); if (prod != null) { MyWeb.encrypt encrypt = new MyWeb.encrypt();