使用 Unity3d 在 Firebase 中存储 DateTime 值的最佳实践

Posted

技术标签:

【中文标题】使用 Unity3d 在 Firebase 中存储 DateTime 值的最佳实践【英文标题】:Best practice for storing DateTime values in Firebase with Unity3d 【发布时间】:2017-12-09 17:12:38 【问题描述】:

我正在构建一个使用 Firebase 作为数据库的 Unity3d 2D 游戏。我需要在数据库中存储大量 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 时,我正在使用 Unitys JsonUtility.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 中存储日期和时间戳的最佳做法的任何帮助/提示?

提前致谢。

【问题讨论】:

【参考方案1】:

好吧,对于其他有这个问题但不想花费数小时拉扯头发的人来说,答案是:你不能(也许不应该,猜这是有原因的)设置ServerValue.Timestamp 对象在您的模型/对象上。

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

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

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&lt;string, object&gt;,因为这是我们从 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 确定正确的时间,而不是使用应用程序的单个客户端。

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

【讨论】:

以上是关于使用 Unity3d 在 Firebase 中存储 DateTime 值的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

无法从unity3d中的firebase实时数据库中检索数据

Unity3d 集成Firebase新中文教程

Unity3d 游戏中集成Firebase 统计和Admob广告最新中文教程

用于 Unity3d Windows 应用程序的 Firebase

如何使用unity3d在Windows Phone的内部存储中创建文件并将其保存到目录中

Firebase 以 firebase:authUser 的形式检索存储在本地存储中的用户数据: