diff --git a/web/App_Code/Model/Partial/files.cs b/web/App_Code/Model/Partial/files.cs index 22574ed..177e524 100644 --- a/web/App_Code/Model/Partial/files.cs +++ b/web/App_Code/Model/Partial/files.cs @@ -23,6 +23,12 @@ namespace Model public virtual ICollection actItem_files { get; set; } } + // TODO: CRITICAL - 靜態字段設計問題(同 follower.cs) + // 權衡:AsEnumerable() vs ToList() + // - AsEnumerable(): 不立即佔內存,但 DbContext 未 Dispose(有風險) + // - ToList(): 立即載入所有 files 到內存(可能很大)且數據過時 + // 建議:改為實例方法或使用緩存機制 + // 暫時保留 AsEnumerable() 避免立即載入大量數據 public static IEnumerable allFiles = new Model.ezEntities().files.AsEnumerable(); } } diff --git a/web/App_Code/Model/Partial/follower.cs b/web/App_Code/Model/Partial/follower.cs index 6e668b5..cacba58 100644 --- a/web/App_Code/Model/Partial/follower.cs +++ b/web/App_Code/Model/Partial/follower.cs @@ -75,6 +75,22 @@ namespace Model Seeker = 10, } + // TODO: CRITICAL - 靜態字段設計問題 + // 【現狀問題】 + // 1. 靜態字段會在類加載時創建新的 DbContext,但從未 Dispose + // 2. ToList() 會立即載入所有 followers 到內存(可能數千筆),佔用大量內存且數據會過時 + // 3. AsEnumerable() 看似更好(延遲執行),但會導致 DbContext 生命週期問題 + // + // 【權衡】 + // - 用 AsEnumerable(): 不立即佔內存,但 DbContext 未 Dispose,後續訪問可能出錯 + // - 用 ToList(): DbContext 可安全關閉,但立即佔用大量內存且數據過時 + // + // 【建議改法】 + // 方案 A: 改為實例方法 `public static List GetAllFollowers() { using(var db = new ezEntities()) return db.followers.ToList(); }` + // 方案 B: 使用緩存機制(MemoryCache)定期更新 + // 方案 C: 完全移除此字段,改為按需查詢 + // + // 暫時保留 AsEnumerable() 避免立即載入大量數據(雖然有 DbContext 問題,但至少不會內存爆掉) public static IEnumerable allFaollowers = new Model.ezEntities().followers.AsEnumerable(); //public static string identity_type_list() diff --git a/web/App_Code/Model/Partial/order.cs b/web/App_Code/Model/Partial/order.cs index 4ee8865..871baa1 100644 --- a/web/App_Code/Model/Partial/order.cs +++ b/web/App_Code/Model/Partial/order.cs @@ -151,7 +151,7 @@ namespace Model .Where(q => q.actItem_num == this.actItem_num) // 同品項 .Where(q => q.print_id != null) // Ensure print_id is not null .Select(q => q.print_id) // Just select the print_id - .AsEnumerable() // Switch to in-memory operations + .AsEnumerable() // ✅ 合理使用:EF 無法轉換 StartsWith/Contains/Replace 到 SQL .Where(q => q.StartsWith(parent_print_id)) // Now do string operations in memory .Where(q => q.Contains(itemPrefix)) .Select(q => q.Trim().Replace("\t", "")) diff --git a/web/App_Code/api/FilesSetController.cs b/web/App_Code/api/FilesSetController.cs index fd8af69..e353db1 100644 --- a/web/App_Code/api/FilesSetController.cs +++ b/web/App_Code/api/FilesSetController.cs @@ -16,6 +16,8 @@ public class FilesSetController : ApiController { private Model.ezEntities _db = new Model.ezEntities(); // GET api/ + // TODO: CRITICAL - 無參數 Get() 會載入所有文件到內存(可能數百筆) + // 建議:停用此方法,強制使用分頁版本 Get(page, pageSize) public IEnumerable Get() { var list = _db.files.ToList(); diff --git a/web/App_Code/api/FollowerController.cs b/web/App_Code/api/FollowerController.cs index 0d841fb..eb8bede 100644 --- a/web/App_Code/api/FollowerController.cs +++ b/web/App_Code/api/FollowerController.cs @@ -19,6 +19,8 @@ public class FollowerController : ApiController { private Model.ezEntities _db = new Model.ezEntities(); // GET api/ + // TODO: CRITICAL - 無參數 Get() 會載入所有信眾到內存(可能數千筆) + // 建議:停用此方法,強制使用分頁版本 Get(page, pageSize) public IEnumerable Get() { var list = _db.followers.ToList(); diff --git a/web/App_Code/api/accountingController.cs b/web/App_Code/api/accountingController.cs index 44ea0c4..91fab35 100644 --- a/web/App_Code/api/accountingController.cs +++ b/web/App_Code/api/accountingController.cs @@ -17,6 +17,8 @@ using static TreeView; public class accountingController : BaseApiController { // GET api/ + // TODO: CRITICAL - 無參數 Get() 會載入所有會計資料到內存(可能數千筆) + // 建議:停用此方法,強制使用分頁版本 Get(page, pageSize) public IEnumerable Get() { var list = _db.accountings.ToList(); diff --git a/web/App_Code/api/activityController.cs b/web/App_Code/api/activityController.cs index dc3ec19..d76189a 100644 --- a/web/App_Code/api/activityController.cs +++ b/web/App_Code/api/activityController.cs @@ -224,7 +224,7 @@ public class activityController : ApiController public IHttpActionResult GetList([FromBody] Model.ViewModel.activity q, int page, int pageSize = 10, string sortBy = "", bool sortDesc = false) { - var qry = _db.activities.AsEnumerable(); + var qry = _db.activities.AsQueryable(); if (!string.IsNullOrEmpty(q.subject)) qry = qry.Where(o => o.subject.Contains(q.subject)); if (q.kind.HasValue && q.kind > 0) @@ -348,7 +348,7 @@ public class activityController : ApiController ////var qry = _db.actItems.Where(a => a.IsDel == false).AsEnumerable();////不確定是否新增欄位? 先註解 - var qry = _db.actItems.AsEnumerable(); + var qry = _db.actItems.AsQueryable(); if (!string.IsNullOrEmpty(q.subject)) qry = qry.Where(o => o.subject.Contains(q.subject.Trim())); @@ -1326,7 +1326,7 @@ public class activityController : ApiController string sortBy = "", bool sortDesc = false) { - var qry = _db.activity_check.AsEnumerable(); + var qry = _db.activity_check.AsQueryable(); if (!string.IsNullOrEmpty(q.activityTxt)) qry = qry.Where(o => o.activity.subject.Contains(q.activityTxt.Trim())); diff --git a/web/App_Code/api/bedController.cs b/web/App_Code/api/bedController.cs index 9321f7a..d11b156 100644 --- a/web/App_Code/api/bedController.cs +++ b/web/App_Code/api/bedController.cs @@ -12,6 +12,8 @@ using System.Collections; public class bedController : BaseApiController { // GET api/ + // TODO: CRITICAL - 無參數 Get() 會載入所有掛單到內存(可能數千筆) + // 建議:停用此方法,強制使用分頁版本 Get(page, pageSize) public IEnumerable Get() { var list = _db.bed_order.ToList(); diff --git a/web/App_Code/api/memberController.cs b/web/App_Code/api/memberController.cs index 2a37b67..166e0e4 100644 --- a/web/App_Code/api/memberController.cs +++ b/web/App_Code/api/memberController.cs @@ -13,6 +13,8 @@ using static TreeView; public class memberController : BaseApiController { // GET api/ + // TODO: CRITICAL - 無參數 Get() 會載入所有會員到內存(可能數百筆) + // 建議:停用此方法,強制使用分頁版本 Get(page, pageSize) public IEnumerable Get() { var list = _db.members.ToList(); diff --git a/web/App_Code/api/newsController.cs b/web/App_Code/api/newsController.cs index 777485c..002e141 100644 --- a/web/App_Code/api/newsController.cs +++ b/web/App_Code/api/newsController.cs @@ -14,6 +14,8 @@ using DocumentFormat.OpenXml.Office2010.Excel; public class newsController : BaseApiController { // GET api/ + // TODO: CRITICAL - 無參數 Get() 會載入所有消息到內存(可能數百筆) + // 建議:停用此方法,強制使用分頁版本 Get(page, pageSize) public IEnumerable Get() { var list = _db.news.ToList(); diff --git a/web/App_Code/api/orderController.cs b/web/App_Code/api/orderController.cs index 8c8501b..2236fec 100644 --- a/web/App_Code/api/orderController.cs +++ b/web/App_Code/api/orderController.cs @@ -21,6 +21,9 @@ public class orderController : ApiController { private Model.ezEntities _db = new Model.ezEntities(); // GET api/ + // TODO: CRITICAL - 無參數 Get() 會載入所有訂單到內存(可能數千筆) + // 建議:停用此方法,強制使用分頁版本 Get(page, pageSize) + // 或改為:return _db.pro_order.AsQueryable(); 讓客戶端決定如何處理 public IEnumerable Get() { var list = _db.pro_order.ToList(); @@ -57,17 +60,17 @@ public class orderController : ApiController // DELETE api//5 public void Delete(string id) { - var prod = _db.pro_order.AsEnumerable().Where(q => q.order_no == id).FirstOrDefault(); //刪除該筆資料 + var prod = _db.pro_order.Where(q => q.order_no == id).FirstOrDefault(); //刪除該筆資料 if (prod != null) { //刪除掛單表單 - var prod3 = _db.bed_order.AsEnumerable().Where(q => q.order_no == id).ToList(); + var prod3 = _db.bed_order.Where(q => q.order_no == id).ToList(); if (prod3.Count > 0) { //刪除掛單明細 foreach (var item3 in prod3) { - var prod4 = _db.bed_order_detail.AsEnumerable().Where(q => q.bed_order_no == item3.bed_order_no).ToList(); + var prod4 = _db.bed_order_detail.Where(q => q.bed_order_no == item3.bed_order_no).ToList(); if (prod4.Count > 0) { _db.bed_order_detail.RemoveRange(prod4); //查詢結果全部刪除 @@ -103,13 +106,13 @@ public class orderController : ApiController if (prod != null) { //刪除掛單表單 - var prod3 = _db.bed_order.AsEnumerable().Where(q => q.order_no == prod.order_no).ToList(); + var prod3 = _db.bed_order.Where(q => q.order_no == prod.order_no).ToList(); if (prod3.Count > 0) //count = 1 { //刪除掛單明細 foreach (var item3 in prod3) { - var prod4 = _db.bed_order_detail.AsEnumerable().Where(q => q.bed_order_no == item3.bed_order_no).ToList(); + var prod4 = _db.bed_order_detail.Where(q => q.bed_order_no == item3.bed_order_no).ToList(); if (prod4.Count > 0) { _db.bed_order_detail.RemoveRange(prod4); //查詢結果全部刪除 @@ -137,17 +140,17 @@ 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.AsEnumerable().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(); if (prod2.Count > 0) { foreach (var item2 in prod2) { - var prod3 = _db.bed_order.AsEnumerable().Where(q => q.order_no == item2.order_no && q.o_detail_id == item2.num).ToList(); + var prod3 = _db.bed_order.Where(q => q.order_no == item2.order_no && q.o_detail_id == item2.num).ToList(); if (prod3.Count > 0) { foreach (var item3 in prod3) { - var prod4 = _db.bed_order_detail.AsEnumerable().Where(q => q.bed_order_no == item3.bed_order_no).ToList(); + var prod4 = _db.bed_order_detail.Where(q => q.bed_order_no == item3.bed_order_no).ToList(); if (prod4.Count > 0) { _db.bed_order_detail.RemoveRange(prod4); @@ -327,7 +330,7 @@ public class orderController : ApiController { int activity = prod.activity_num.HasValue ? prod.activity_num.Value : 0; //活動 - var bedDt = _db.bed_order_detail.AsEnumerable().Where(b => b.bed_order.order_no == order_no); ;//掛單明細 + var bedDt = _db.bed_order_detail.Where(b => b.bed_order.order_no == order_no); ;//掛單明細 //var qry1 = _db.pro_order_detail.AsEnumerable(); @@ -1080,7 +1083,7 @@ public class orderController : ApiController if (detail_num > 0) { //檢查 - var prod = _db.pro_order_record.AsEnumerable().Where(o => o.detail_num == detail_num) + var prod = _db.pro_order_record.Where(o => o.detail_num == detail_num) .OrderByDescending(o => o.pay_date).ToList(); int i = 1; @@ -1134,8 +1137,8 @@ public class orderController : ApiController { if (item.detail_num > 0) { - float total = _db.pro_order_detail.AsEnumerable().Where(x => x.num == item.detail_num).Select(x => x.price.Value * x.qty.Value).Sum(); - float pay = _db.pro_order_record.AsEnumerable().Where(x => x.detail_num == item.detail_num).Select(x => x.price.Value).Sum(); + float total = _db.pro_order_detail.Where(x => x.num == item.detail_num).Select(x => x.price.Value * x.qty.Value).Sum(); + float pay = _db.pro_order_record.Where(x => x.detail_num == item.detail_num).Select(x => x.price.Value).Sum(); if (pay + item.price.Value <= total) { diff --git a/web/App_Code/api/projectController.cs b/web/App_Code/api/projectController.cs index 82660a9..9ef9193 100644 --- a/web/App_Code/api/projectController.cs +++ b/web/App_Code/api/projectController.cs @@ -13,6 +13,8 @@ using static TreeView; public class projectController : BaseApiController { // GET api/ + // TODO: CRITICAL - 無參數 Get() 會載入所有專案到內存(可能數百筆) + // 建議:停用此方法,強制使用分頁版本 Get(page, pageSize) public IEnumerable Get() { var list = _db.projects.ToList(); diff --git a/web/App_Code/api/stockController.cs b/web/App_Code/api/stockController.cs index 015d842..26c560b 100644 --- a/web/App_Code/api/stockController.cs +++ b/web/App_Code/api/stockController.cs @@ -19,6 +19,8 @@ using DocumentFormat.OpenXml.Office2010.Excel; public class stockController : BaseApiController { // GET api/ + // TODO: CRITICAL - 無參數 Get() 會載入所有庫存到內存(可能數千筆) + // 建議:停用此方法,強制使用分頁版本 Get(page, pageSize) public IEnumerable Get() { var list = _db.stocks.ToList(); diff --git a/web/App_Code/api/supplierController.cs b/web/App_Code/api/supplierController.cs index 90e7212..59b6021 100644 --- a/web/App_Code/api/supplierController.cs +++ b/web/App_Code/api/supplierController.cs @@ -15,6 +15,8 @@ using iTextSharp.text.pdf.qrcode; public class supplierController : BaseApiController { // GET api/ + // TODO: REVIEW - 無參數 Get() 會載入所有供應商到內存 + // 若供應商數量少(<100),可接受;若會成長,建議停用此方法 public IEnumerable Get() { var list = _db.suppliers.ToList(); diff --git a/web/App_Code/api/transfer_registerController.cs b/web/App_Code/api/transfer_registerController.cs index e9bf456..808cbe6 100644 --- a/web/App_Code/api/transfer_registerController.cs +++ b/web/App_Code/api/transfer_registerController.cs @@ -17,6 +17,8 @@ public class transfer_registerController : ApiController private Model.ezEntities _db = new Model.ezEntities(); // GET api/transfer_register + // TODO: CRITICAL - 無參數 Get() 會載入所有登記到內存(可能數千筆) + // 建議:停用此方法,強制使用分頁版本 Get(page, pageSize) public IEnumerable Get() { var list = _db.transfer_register.ToList(); diff --git a/web/App_Code/appapi/appFollowerController.cs b/web/App_Code/appapi/appFollowerController.cs index 2d9e174..967ea6f 100644 --- a/web/App_Code/appapi/appFollowerController.cs +++ b/web/App_Code/appapi/appFollowerController.cs @@ -54,7 +54,7 @@ public class appFollowerController : ApiController // DELETE api//5 public void Delete(int id) { - var prod = _db.followers.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料 + var prod = _db.followers.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料 if (prod != null) { @@ -82,9 +82,9 @@ public class appFollowerController : ApiController { if (!string.IsNullOrEmpty(nums)) { - var getDelItem = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s)); + var getDelItem = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s)).ToList(); - var prod = _db.followers.AsEnumerable().Where(q => getDelItem.Contains(q.num)).ToList(); + var prod = _db.followers.Where(q => getDelItem.Contains(q.num)).ToList(); if (prod.Count() > 0) { foreach (var item in prod) @@ -127,7 +127,7 @@ public class appFollowerController : ApiController public IHttpActionResult GetList([FromBody] Model.ViewModel.follower q, int page, int pageSize = 10, string sortBy = "", bool sortDesc = false) { - var qry = _db.followers.AsEnumerable(); + var qry = _db.followers.AsQueryable(); if (!string.IsNullOrEmpty(q.f_number)) qry = qry.Where(o => o.f_number.Contains(q.f_number.Trim())); @@ -138,7 +138,7 @@ public class appFollowerController : ApiController if (q.birthday2.HasValue) qry = qry.Where(o => o.birthday < Convert.ToDateTime(q.birthday2.Value).AddDays(1)); if (!string.IsNullOrEmpty(q.address)) - qry = qry.Where(o => o.address !=null && o.address.Contains(q.address?.Trim())); + qry = qry.Where(o => o.address !=null && o.address.Contains(q.address.Trim())); //if (q.num.HasValue && q.num.Value>0) // qry = qry.Where(o => o.num==q.num.Value); if (q.ept_self.HasValue && q.ept_self.Value )//排除自己 @@ -292,7 +292,7 @@ public class appFollowerController : ApiController - var qry = _db.followers.AsEnumerable().Where(f => cc.Any(x => x == f.num) || cc.Any(x => x == f.leader)); + var qry = _db.followers.Where(f => cc.Contains(f.num) || (f.leader.HasValue && cc.Contains(f.leader.Value))); @@ -474,7 +474,7 @@ public class appFollowerController : ApiController if (_follower > 0) { - var qry = _db.followers_tablet.AsEnumerable().Where(x=>( x.f_num??0) == _follower); + var qry = _db.followers_tablet.Where(x=>( x.f_num??0) == _follower); qry = qry.OrderByDescending(o => o.num); int i = 1; var ret = new @@ -542,7 +542,7 @@ public class appFollowerController : ApiController [Route("api/appfollower/tabletDelete/{id}")] public void tabletDelete(int id) { - var prod = _db.followers_tablet.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料 + var prod = _db.followers_tablet.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料 if (prod != null) { _db.followers_tablet.Remove(prod); diff --git a/web/App_Code/appapi/apporderController.cs b/web/App_Code/appapi/apporderController.cs index 94b5571..45dda32 100644 --- a/web/App_Code/appapi/apporderController.cs +++ b/web/App_Code/appapi/apporderController.cs @@ -199,7 +199,7 @@ public class apporderController : ApiController string sortBy = "", bool sortDesc = false) { - var qry = _db.pro_order.AsEnumerable(); + var qry = _db.pro_order.AsQueryable(); //var aIDt = _db.actItems.Where(f => f.subject.Contains(q.actItemTxt.Trim())).Select(f => f.num);//品項 @@ -273,16 +273,16 @@ public class apporderController : ApiController else if (sortBy.Equals("u_name")) { if (sortDesc) - qry = qry.OrderByDescending(o => o.follower?.u_name); + qry = qry.OrderByDescending(o => o.follower != null ? o.follower.u_name : ""); else - qry = qry.OrderBy(o => o.follower?.u_name); + qry = qry.OrderBy(o => o.follower != null ? o.follower.u_name : ""); } else if (sortBy.Equals("subject")) { if (sortDesc) - qry = qry.OrderByDescending(o => o.activity?.subject); + qry = qry.OrderByDescending(o => o.activity != null ? o.activity.subject : ""); else - qry = qry.OrderBy(o => o.activity?.subject); + qry = qry.OrderBy(o => o.activity != null ? o.activity.subject : ""); } else qry = qry.OrderByDescending(o => o.reg_time); @@ -326,7 +326,7 @@ public class apporderController : ApiController //var qry1 = _db.pro_order_detail.AsEnumerable(); //qry1 = qry1.Where(o => o.order_no == order_no); - var qry1 = prod.pro_order_detail.AsEnumerable(); + var qry1 = prod.pro_order_detail.AsQueryable(); //if (!string.IsNullOrEmpty(q.subject)) // qry = qry.Where(o => o.subject.Contains(q.subject)); @@ -357,10 +357,10 @@ public class apporderController : ApiController int i = 1; //已有值 - if (pageSize > 0) qry1 = qry1.ToPagedList(page, pageSize); + var qryList = pageSize > 0 ? qry1.ToPagedList(page, pageSize).ToList() : qry1.ToList(); var ret = new { - list = qry1.Select(x => new + list = qryList.Select(x => new { id = i++, num = x.num, @@ -391,7 +391,7 @@ public class apporderController : ApiController writeBedQty = bedDt.Where(b=>b.bed_order.o_detail_id.Value== x.num && b.checkIn_date.HasValue && b.bed_kind_detail_id.HasValue).Count(), //已劃數量 notBedQty = bedDt.Where(b=>b.bed_order.o_detail_id.Value== x.num &&( !b.checkIn_date.HasValue || !b.bed_kind_detail_id.HasValue)).Count(), //未劃數量 //total = x.total.HasValue ? x.total.Value : 0, - category = x.actItem?.category, + category = x.actItem_num.HasValue ? x.actItem.category : (int?)null, //pay = x.pay ?? 0, pay = x.pro_order_record.Select(c => c.price).Sum(), pay_date = x.pay_date, @@ -401,14 +401,14 @@ public class apporderController : ApiController val = x.keyin1, }, demo = x.demo, - files = x.actItem?.actItem_files.Select(f => new + files = x.actItem_num.HasValue ? x.actItem.actItem_files.Select(f => new { num = f.file.num, subject = f.file.subject, word = f.file.word, cuz_column = f.file.customize_data??"", //?? paperset = f.file.paperset ?? "", - }), + }) : null, customize_data =x.customize_data??"", customize_data_comb = new {