使用 Unity3d 在 Firebase 中存储日期时间值的最佳做法



我正在构建一个Unity3d 2D游戏,我使用Firebase作为数据库。我需要在数据库中存储相当多的DateTime值(作为 UTC),我想知道这样做的最佳实践是什么。

DateTime字段将主要用于排序/过滤。

根据Firebase文档,我应该使用Firebase.Database.ServerValues.TIMESTAMP,这只是一个object

问题是,我正在为我的 Unity 游戏使用强类型模型,如下所示:

[Serializable]
public class Profile {
[NonSerialized]
public string ProfileKey;
// Serializable attributes
public string userId;
public string name;
public int age;
public string gender; // "M" or "F"
public DateTime utcCreated; // UTC   
public DateTime utcUpdated; // UTC
}   

当我保存/更新Profile时,我使用的是 UnitysJsonUtility.ToJson()方法,如下所示:

var profiles = db.Child ("profiles");
Profile profile = new Profile {
userId = GameManager.Instance.User.UserId,
name = "My new profile",
age = 23,
gender = "M",
utcCreated = ?? // Should somehow use Firebase.Database.ServerValues.TIMESTAMP here, I guess?
};              
string json = JsonUtility.ToJson (profile);     
var profileKey = profiles.Push ().Key;
profiles.Child (profileKey).SetRawJsonValueAsync (json, 1).ContinueWith (t => {
// .. handle response here
});

我不确定我应该在我的模型上将utcCreated字段设置为什么。尝试简单地使该字段成为object,但没有将任何值插入到Firebase中。还试图使其成为一个字符串,.ToString()Firebase.Database.ServerValues.TIMESTAMP对象,但没有在 Firebase 中插入任何值。

有谁知道如何做到这一点? ;-)或者只是关于在 Firebase 中存储日期和时间戳的最佳实践的任何帮助/提示?

提前谢谢。

好吧,对于其他有这个问题的人,他们不想花几个小时的沮丧时间,答案是:你不能(也许不应该,猜猜是有原因的)在你的模型/对象上设置ServerValue.Timestamp对象。

ServerValue.Timestamp是您通过调用SetValueAsync()UpdateChildrenAsync()在 Firebase 文档中专门设置的内容

所以我所做的是向我的Profile类添加两个字段:一个表示 unix 时间戳服务器值,另一个表示 unix 时间戳服务器值作为 C#DateTime对象:

using System;
using System.Collections.Generic;
using System.Linq;
[Serializable]
public class Profile
{
[NonSerialized]
public string profileKey;
[NonSerialized]
public long utcCreatedTimestamp;
[NonSerialized]
public DateTime utcCreated;
// Serializable attributes
public string userId;
public string name;
public int age;
public string gender; // "M" or "F"
public Profile() { }
public Profile(Dictionary<string, object> fromFirebaseResult)
{
userId = fromFirebaseResult.ContainsKey("userId") ? fromFirebaseResult.First(x => x.Key == "userId").Value.ToString() : string.Empty;
name = fromFirebaseResult.ContainsKey("name") ? fromFirebaseResult.First(x => x.Key == "name").Value.ToString() : string.Empty;
age = fromFirebaseResult.ContainsKey("age") ? int.Parse(fromFirebaseResult.First(x => x.Key == "age").Value.ToString()) : 0;
gender = fromFirebaseResult.ContainsKey("gender") ? fromFirebaseResult.First(x => x.Key == "gender").Value.ToString() : string.Empty;
if (fromFirebaseResult.ContainsKey("utcCreatedUnix")) {
long milliseconds;
if(long.TryParse(fromFirebaseResult.First(x => x.Key == "utcCreatedUnix").Value.ToString(), out milliseconds)) {
utcCreatedTimestamp = milliseconds;
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
utcCreated = epoch.AddMilliseconds(milliseconds);
}
}
}
}

Profile类有一个默认的构造函数和一个构造函数,这需要Dictionary<string, object>,因为这是我们从 Unity 查询时从 Firebase 获得的。

将新Profile保存到 Firebase 时,我会创建一个新的Profile对象,而不设置与日期和时间相关的任何内容。将其保存在 Firebase 中,然后调用UpdateChildrenAsync以设置 Firebase 中的utcCreatedUnix字段。这样:

DatabaseReference db = FirebaseDatabase.DefaultInstance.RootReference;
// Get the user id
string userId = GameManager.Instance.User.UserId;
// Get a reference to the profiles
var profiles = db.Child("profiles");
// Create a new serializable profile
Profile profile = new Profile {
userId = userId,
name = "Bo Mortensen",
age = 34,
gender = "M"
};              
// Serialize profile to JSON
string json = JsonUtility.ToJson (profile);     
// Push a new document to the database
var profileKey = profiles.Push ().Key;
// Set JSON for this document
profiles.Child (profileKey).SetRawJsonValueAsync (json, 1).ContinueWith (t => {
if (t.IsCompleted) {
// Assign the profile key (unique key generated by Firebase) to the profile
profile.profileKey = profileKey;
// Set the Firebase server timestamp on the datetime object
profiles.Child(profileKey).UpdateChildrenAsync(new Dictionary<string, object> { { "utcCreatedUnix", ServerValue.Timestamp } });
}
});

从 Firebase 获取Profile文档时,我现在可以执行以下操作:

var db = FirebaseDatabase.DefaultInstance.RootReference;
var profileRef = db.Child("profiles/MyProfileKey");
profileRef.GetValueAsync().ContinueWith(t =>
{
var values = t.Result.Value as System.Collections.Generic.Dictionary<string, object>;
// Let the constructor populate the fields
Profile profile = new Profile(values)
{
profileKey = profileRef.Key
};

DateTime createdDate = profile.utcCreated;
});

您可能会问为什么我不只是存储一个我可以这样做的DateTime.UtcNow.ToString(),但我不想依赖客户端时钟设置。通过使用 Firebase ServerValue.Timestamp,Firebase 可以确定正确的时间,而不是使用该应用程序的单个客户端。

希望这对其他任何人有帮助:-)

最新更新