运行时创建Firestore动态查询的最优实现方案是什么?
针对Firestore动态字段监听场景的解决方案
不需要在运行时动态创建带FirestoreData特性的类,Firestore .NET SDK原生支持无强类型的字段读取方式,完全适配直播场景动态字段的需求,以下是具体实现方案:
方案1:用Dictionary接收动态Map字段(最推荐)
Firestore的GetValue方法支持直接传入Dictionary<string, object>作为泛型参数,可自动把任意Map类型的字段解析为字典,不管内部有多少未知键值对都可以正常读取,示例代码如下:
/// <param name="dynamicQuestionPath">动态查询路径,比如运行时生成的 "questions.q3" "questions.q5" 等</param> public void GetDynamicDataFeed(string dynamicQuestionPath) { FirebaseFirestore db = FirebaseFirestore.DefaultInstance; DocumentReference aggs = db.Collection("aggregations").Document("s1e1"); ListenerRegistration aggregation = aggs.Listen(snapshot => { // 动态路径直接传变量,返回字典适配所有未知字段 Dictionary<string, object> questionData = snapshot.GetValue<Dictionary<string, object>>(dynamicQuestionPath); // 遍历所有未知字段读取值 foreach (var field in questionData) { Debug.Log($"字段名:{field.Key},值:{field.Value}"); } // 如果有部分已知固定字段也可以直接取值 if (questionData.ContainsKey("I do")) { Debug.Log(questionData["I do"].ToString()); } }); }
如果存在多层嵌套Map,把对应Value再转成Dictionary<string, object>即可继续读取下层字段。
方案2:直接通过Snapshot索引器动态读取字段
如果连字段路径的层级都是完全动态的,可以直接用DocumentSnapshot的原生方法逐层读取,不需要提前定义任何数据类型:
/// <param name="fieldPathSegments">动态拆分的字段路径层级,比如 ["questions", "q3", "I do"]</param> public void GetDynamicFieldValue(List<string> fieldPathSegments) { FirebaseFirestore db = FirebaseFirestore.DefaultInstance; DocumentReference aggs = db.Collection("aggregations").Document("s1e1"); ListenerRegistration aggregation = aggs.Listen(snapshot => { object currentValue = snapshot; foreach (var segment in fieldPathSegments) { if (currentValue is DocumentSnapshot snap) { currentValue = snap[segment]; } else if (currentValue is Dictionary<string, object> dict) { currentValue = dict[segment]; } else { // 路径不存在时的异常处理 currentValue = null; break; } } if (currentValue != null) { Debug.Log($"动态字段值:{currentValue}"); } }); }
性能优化:仅监听指定字段变更
直播场景并发量高,不需要全文档变更都触发回调,可以指定仅监听你需要的动态字段变更,SDK会自动过滤无关的更新事件:
// 动态拼接需要监听的字段路径 FieldPath dynamicField = new FieldPath("questions", "q3"); // 只有指定字段变更时才会触发回调 aggs.Listen(new[] { dynamicField }, snapshot => { Dictionary<string, object> questionData = snapshot.GetValue<Dictionary<string, object>>(dynamicField); // 后续业务逻辑 });
关于动态创建类的说明
运行时通过Emit生成带Firestore特性的类不仅开发复杂度高,还要处理属性绑定、类型转换等大量边界问题,性能也远低于直接用字典读取,完全没有必要采用该方案。
内容的提问来源于stack exchange,提问作者Iain Simons
相关产品推荐
相关产品推荐

