修正多處 LINQ-to-Entities 查詢,避免 Nullable .Contains()、.ToString()、Request[] 直接使用造成翻譯失敗。

API 查詢同步改寫 .Contains()、.OrderBy()、複雜 GroupBy/Math.Round,必要時 materialize 或加 HasValue。
Participation rate / kind breakdown 改在記憶體計算,同時檢查整數陣列 .Contains() 的型別安全性。
This commit is contained in:
2025-11-14 23:40:55 +08:00
parent 4fcbfb3801
commit 27f916eb9c
14 changed files with 245 additions and 115 deletions

View File

@@ -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 → SumEF 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 → SumEF 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;