STAGE 3-4

This commit is contained in:
2025-11-12 18:57:51 +08:00
parent 744eddcd77
commit ae09a6f487
17 changed files with 80 additions and 35 deletions

View File

@@ -23,6 +23,12 @@ namespace Model
public virtual ICollection<actItem_files> actItem_files { get; set; }
}
// TODO: CRITICAL - 靜態字段設計問題(同 follower.cs
// 權衡AsEnumerable() vs ToList()
// - AsEnumerable(): 不立即佔內存,但 DbContext 未 Dispose有風險
// - ToList(): 立即載入所有 files 到內存(可能很大)且數據過時
// 建議:改為實例方法或使用緩存機制
// 暫時保留 AsEnumerable() 避免立即載入大量數據
public static IEnumerable<Model.file> allFiles = new Model.ezEntities().files.AsEnumerable();
}
}

View File

@@ -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<follower> GetAllFollowers() { using(var db = new ezEntities()) return db.followers.ToList(); }`
// 方案 B: 使用緩存機制MemoryCache定期更新
// 方案 C: 完全移除此字段,改為按需查詢
//
// 暫時保留 AsEnumerable() 避免立即載入大量數據(雖然有 DbContext 問題,但至少不會內存爆掉)
public static IEnumerable<Model.follower> allFaollowers = new Model.ezEntities().followers.AsEnumerable();
//public static string identity_type_list()

View File

@@ -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", ""))

View File

@@ -16,6 +16,8 @@ public class FilesSetController : ApiController
{
private Model.ezEntities _db = new Model.ezEntities();
// GET api/<controller>
// TODO: CRITICAL - 無參數 Get() 會載入所有文件到內存(可能數百筆)
// 建議:停用此方法,強制使用分頁版本 Get(page, pageSize)
public IEnumerable<Model.file> Get()
{
var list = _db.files.ToList();

View File

@@ -19,6 +19,8 @@ public class FollowerController : ApiController
{
private Model.ezEntities _db = new Model.ezEntities();
// GET api/<controller>
// TODO: CRITICAL - 無參數 Get() 會載入所有信眾到內存(可能數千筆)
// 建議:停用此方法,強制使用分頁版本 Get(page, pageSize)
public IEnumerable<Model.follower> Get()
{
var list = _db.followers.ToList();

View File

@@ -17,6 +17,8 @@ using static TreeView;
public class accountingController : BaseApiController
{
// GET api/<controller>
// TODO: CRITICAL - 無參數 Get() 會載入所有會計資料到內存(可能數千筆)
// 建議:停用此方法,強制使用分頁版本 Get(page, pageSize)
public IEnumerable<Model.accounting> Get()
{
var list = _db.accountings.ToList();

View File

@@ -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()));

View File

@@ -12,6 +12,8 @@ using System.Collections;
public class bedController : BaseApiController
{
// GET api/<controller>
// TODO: CRITICAL - 無參數 Get() 會載入所有掛單到內存(可能數千筆)
// 建議:停用此方法,強制使用分頁版本 Get(page, pageSize)
public IEnumerable<Model.bed_order> Get()
{
var list = _db.bed_order.ToList();

View File

@@ -13,6 +13,8 @@ using static TreeView;
public class memberController : BaseApiController
{
// GET api/<controller>
// TODO: CRITICAL - 無參數 Get() 會載入所有會員到內存(可能數百筆)
// 建議:停用此方法,強制使用分頁版本 Get(page, pageSize)
public IEnumerable<Model.member> Get()
{
var list = _db.members.ToList();

View File

@@ -14,6 +14,8 @@ using DocumentFormat.OpenXml.Office2010.Excel;
public class newsController : BaseApiController
{
// GET api/<controller>
// TODO: CRITICAL - 無參數 Get() 會載入所有消息到內存(可能數百筆)
// 建議:停用此方法,強制使用分頁版本 Get(page, pageSize)
public IEnumerable<Model.news> Get()
{
var list = _db.news.ToList();

View File

@@ -21,6 +21,9 @@ public class orderController : ApiController
{
private Model.ezEntities _db = new Model.ezEntities();
// GET api/<controller>
// TODO: CRITICAL - 無參數 Get() 會載入所有訂單到內存(可能數千筆)
// 建議:停用此方法,強制使用分頁版本 Get(page, pageSize)
// 或改為return _db.pro_order.AsQueryable(); 讓客戶端決定如何處理
public IEnumerable<Model.pro_order> Get()
{
var list = _db.pro_order.ToList();
@@ -57,17 +60,17 @@ public class orderController : ApiController
// DELETE api/<controller>/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)
{

View File

@@ -13,6 +13,8 @@ using static TreeView;
public class projectController : BaseApiController
{
// GET api/<controller>
// TODO: CRITICAL - 無參數 Get() 會載入所有專案到內存(可能數百筆)
// 建議:停用此方法,強制使用分頁版本 Get(page, pageSize)
public IEnumerable<Model.project> Get()
{
var list = _db.projects.ToList();

View File

@@ -19,6 +19,8 @@ using DocumentFormat.OpenXml.Office2010.Excel;
public class stockController : BaseApiController
{
// GET api/<controller>
// TODO: CRITICAL - 無參數 Get() 會載入所有庫存到內存(可能數千筆)
// 建議:停用此方法,強制使用分頁版本 Get(page, pageSize)
public IEnumerable<Model.stock> Get()
{
var list = _db.stocks.ToList();

View File

@@ -15,6 +15,8 @@ using iTextSharp.text.pdf.qrcode;
public class supplierController : BaseApiController
{
// GET api/<controller>
// TODO: REVIEW - 無參數 Get() 會載入所有供應商到內存
// 若供應商數量少(<100可接受若會成長建議停用此方法
public IEnumerable<Model.supplier> Get()
{
var list = _db.suppliers.ToList();

View File

@@ -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<Model.transfer_register> Get()
{
var list = _db.transfer_register.ToList();

View File

@@ -54,7 +54,7 @@ public class appFollowerController : ApiController
// DELETE api/<controller>/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);

View File

@@ -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
{