C# .net asp
專案要做一個道具系統 伺服器端
最基本就是必須有ID和Amount兩個欄位去紀錄所有道具的數量
目前想到的兩個方案
方案一 用道具編號當作欄位名稱 Amount記在這個欄位的值
方案二 個欄位叫做itemId記錄道具ID 有一個欄位叫value紀錄道具數量
目前想到及遇到的問題
關於方案一
問題一
因為道具種類會非常多 可能上百種
(例如會有item_78910 ~ item_526284, 也不一定是連續數字)
那欄位有數量限制嗎?
欄位數量過多會影響效能嗎?
問題二
要如何知道這個LCObject有幾個欄位?
目前查看LCObject上的函式沒看到有函式會把estimatedData的keys傳出來
從名稱上看有一個懷疑的函式GetUpdatedKeys
但是這個函式永遠都給我Null
主要會使用在客戶端向伺服器拉取所有道具時會用到
或是客戶端要顯示UI時要列出所有道具
沒有這個功能的話只能for從最小到最大檢查this["item_{id}"]!=null
覺得這樣不太合理
方案一的消耗道具程式寫法
var user = await LCUser.BecomeWithSessionToken(LCEngineRequestContext.SessionToken);
// 要消耗的道具及數量 <itemId, amount>
var consumeItems = new Dictionary<int, int>()
{
{ 123, 1 },
{ 456, 2 },
};
// 拉出objectId
var query = new LCQuery<LCObject>(ItemDataClassName);
query.WhereEqualTo("ownerId", user.ObjectId);
query.Select("objectId");
var itemData = await query.First();
// 消耗道具
var consumeRequest = LCObject.CreateWithoutData(ItemDataClassName, itemData.ObjectId);
var condition = new LCQuery<LCObject>(ItemDataClassName);
foreach (var kv in consumeItems)
{
var column = $"item_{kv.Key}";
consumeRequest.Increment(column, -kv.Value);
condition.WhereGreaterThanOrEqualTo(column, kv.Value);
}
try
{
var result = await consumeRequest.Save(true, condition);
// 成功
return "ok";
}
catch (Exception ex)
{
// 失敗 不足
return "insufficient";
}
關於方案二
問題一
這個方案很明顯在同時需要增減多種道具數量時要發送多個request
而且也不能使用Object.SaveAll去操作
原因是在使用道具有可能失敗 當其中一個道具使用失敗時 要把其他消耗的道具還原
這樣來來回回就會產生很多的request
問題二
承上一個問題
當同時操作多個LCObject時如果不能使用Object.SaveAll
那就有可能出現錯誤(429 信息 - Too many requests)
為了避免發生 必須一個一個道具線性的操作(或是有限度的平行化)
增長了整體API的反應時間,loading大時遇到超時的機會比較高
方案二的消耗道具程式寫法
var user = await LCUser.BecomeWithSessionToken(LCEngineRequestContext.SessionToken);
// 要消耗的道具及數量 <itemId, amount>
var consumeItems = new Dictionary<int, int>()
{
{ 123, 1 },
{ 456, 2 },
};
// 拉出objectId
var query = new LCQuery<LCObject>(ItemDataClassName2);
query.WhereEqualTo("ownerId", user.ObjectId);
query.WhereContainedIn("itemId", consumeItems.Keys);
var itemDatas = new List<LCObject>(await query.Find());
// 消耗道具
var failed = false;
var succeedItems = new List<ValueTuple<int, string>>(); // itemId , lc objectId
foreach (var kv in consumeItems)
{
try
{
var itemId = kv.Key;
var amount = kv.Value;
var itemData = itemDatas.Find(obj => itemId == (int)obj["itemId"]);
var consumeRequest = LCObject.CreateWithoutData(ItemDataClassName2, itemData.ObjectId);
var condition = new LCQuery<LCObject>(ItemDataClassName2);
consumeRequest.Increment("value", -amount);
condition.WhereGreaterThanOrEqualTo("value", amount);
var result = await consumeRequest.Save(true, condition);
// success
succeedItems.Add((itemId, itemData.ObjectId));
}
catch (Exception ex)
{
// 失敗 不足
failed = true;
break;
}
}
if (failed)
{
// 還原已扣除
foreach (var pair in succeedItems)
{
var itemId = pair.Item1;
var objectId = pair.Item2;
var revertRequest = LCObject.CreateWithoutData(ItemDataClassName2, objectId);
revertRequest.Increment("value", consumeItems[itemId]);
await revertRequest.Save();
}
// 失敗 不足
return "insufficient";
}
else
{
// 成功
return "ok";
}
請問使用哪種思路會比較適合
還是有更好的思路 歡迎提出來
謝謝指教