【问题标题】:Firebase data - error converting valueFirebase 数据 - 错误转换值
【发布时间】:2018-08-27 17:25:04
【问题描述】:

我两天前发布了有关 firebase 的问题: Android Firebase - add authenticated user into database

我得到了我需要的帮助,这解决了第一个问题。但现在我有一个新问题。我在谷歌上搜索了很长一段时间,有一些关于这个问题的帖子,但没有解决我的问题。我不想在上一个问题中发送垃圾邮件,所以我发布了一个新问题。

当我尝试从 firebase 数据库中读取插入的数据时,出现以下错误:

Newtonsoft.Json.JsonSerializationException:转换值时出错 “test@user.com”键入“carServiceApp.My_Classes.Account”。小路 “电子邮件”,第 1 行,第 24 位。

代码如下:

 private async Task LoadData()
    {
        FirebaseUser users = FirebaseAuth.GetInstance(loginActivity.app).CurrentUser;
        id = users.Uid;

        var firebase = new FirebaseClient(loginActivity.FirebaseURL);
        var items = await firebase.Child("users").Child(id).OnceAsync<Account>();


        foreach (var item in items)
        {
            Account user = new Account();
            user.uid = item.Object.uid;
            user.name = item.Object.name;
            user.lastName = item.Object.lastName;
            user.phone = item.Object.phone;
            user.email = item.Object.email;

            userInput_ime.Text = user.name;
            userInput_prezime.Text = user.lastName;
            userInput_broj.Text = user.phone;
            userInput_email.Text = user.email;
        }

    }

这是 Firebase 数据:

-users
    -jwAP2dYNzJeiF3QlmEIEQoruUkO2
       email: "test@user.com"
       lastName: "user"
       name: "test"
       phone: "12421"
       uid: "jwAP2dYNzJeiF3QlmEIEQoruUkO2"

有趣的是,当我尝试用这个读取数据时:

var items = await firebase.Child("users").OnceAsync<Account>();

这很好用(我得到了最后插入的用户)。但是当我添加'uid' 节点时,我得到了错误。我试图解决这个问题已经有一段时间了,但我就是想不通。我猜想帐户类没有问题,因为它在没有uid 节点的情况下工作,但在添加另一个child() 方法时不起作用。

您可以在顶部的链接中查看其他信息(帐户类代码和将该数据存储到数据库中的方式)。

注意:我尝试在 Account 类中添加构造函数,但这没有帮助。

【问题讨论】:

  • 我认为问题的原因很简单,因为 JsonConvert 序列化程序区分大小写“电子邮件”和“电子邮件”不同,为什么不尝试在帐户属性中进行此更改并检查一下
  • @G.hakim 已经尝试过了。没用。
  • 而且,正如我所说,当我尝试在没有最后一个子节点(uid 节点)的情况下读取数据时,它一切正常,它只选择最后一个输入的用户。但是我希望选择特定的用户,这就是为什么我添加了该 uid 节点以及添加最后一个子节点时(读取数据时)出现上述错误。

标签: c# json firebase firebase-realtime-database xamarin.android


【解决方案1】:

好的,所以我没有完全找到解决这个问题的方法,我也不太明白为什么会发生这种情况,但我找到了解决方法。我认为这不是理想的解决方案,也不能解决现有问题。或者也许是我不理解 Firebase 逻辑的问题,但这是我想出的。

因此,考虑到如果我没有指定该 uid 节点一切正常,那么很明显,firebase 中的类和数据存在一些问题,我猜是匹配问题。无论如何,我决定拥有最后一个 uid 节点,这样我就可以选择特定的用户,并在 firebase 中拥有相同的数据,以防万一一切正常。所以,这就是我将数据插入 firebase 的方式:

  var item = firebase.Child("users").Child(id).PostAsync<Account>(user);

这创建了用户节点和子节点。 PostAsync 方法使用随机密钥再创建一个节点。 因此,当我尝试阅读时:

var data = await firebase.Child("users").Child(id).OnceAsync<Account>();

它没有问题。现在 firebase 数据如下所示:

   users
     JPKdQbwcXbhBatZ2ihBNLRauhV83
        -LCXyLpvdfQ448KOPKUp 
              email:  "spider@man.com"
              lastName:  "man"
              name:  "spider"
              phone:  "14412"
              uid: "JPKdQbwcXbhBatZ2ihBNLRauhV83"

有一点冗余,我基本上有两个 ID,但我不明白如何创建我的类,所以我可以通过任何其他方式获取这些数据,所以我这样做了。它工作正常。

如果有人有更好的解决方案,我很乐意改变它。干杯

【讨论】:

    【解决方案2】:

    这应该是评论,但这只是假设任何需要帮助解决此问题的人的补充。

    我知道这个答案已经有一段时间了,但这似乎仍然是 Firebase 的一个运行结构怪癖及其规则的使用。我遇到了一个看起来像这样的复杂结构的问题

    -Orders
        -9876trfghji (User ID)
         -0
           BusnID: "ty890oihg"
           Name: "Some Name"
           AddOns: Object
           ItemData: Object(containing other objects)
           UserID: "9876trfghji"
    

    注意:在这种情况下以及使用 cordas 的情况下,您会看到两个最终对象都有一个 UserID 或 uid。

    当对象数据被发送回设备时,我还遇到了对象的类反序列化问题,而对象数据中没有实际的用户 ID。

    您对用户 ID 进行“冗余”使用的原因是出于 Firebase 规则的安全措施。具有上述结构的第一个 UserID 可以根据用户 ID 控制对信息的访问,而无需在规则中添加额外的验证子句。目前截至本文,以下规则将根据用户 ID 保护数据。

    “Orders” : {
            "$uid":{
                      ".read":"auth != null",
                      ".write":"auth.uid == $uid"
                    }
        }
    

    这允许仅具有授权用户 ID 的用户写入内容,但任何拥有有效凭据的人都可以查看数据。

    必须将第二个用户 ID 放置在对象中,因为没有它,您将无法对对象执行标准转换,因为您的对象将没有创建对象所需的所有数据。无论您使用的是 GoogleGson 还是 Newtonsoft.Json 之类的包,对象仍然没有满。

    除了将用户 ID 重新输入到对象中之外,还有其他方法可以解决此问题。对于上面的对象,我决定在我的个人代码中重新输入用户 ID,以节省手动创建的时间和麻烦。

    使用 Firebase.Database NuGet 包,您可以手动创建对象。这是cordas问题中的对象示例

        public static void GetUser_Firebase(User user, FirebaseApp app)
        {
        FirebaseDatabase database = FirebaseDatabase.GetInstance(app);
        DatabaseReference reference = database.GetReference($"/users/{user.UserID}");
        //"Using for getting firebase information", $"/users/{user.UserID}"
        reference.AddListenerForSingleValueEvent(new UserInfo_DataValue());
        }
    
    class UserInfo_DataValue : Java.Lang.Object, IValueEventListener
    {
        private string ID;
     public UserInfo_DataValue(string uid)
     {
          this.ID = uid;
        }
        public void OnCancelled(DatabaseError error)
        {
            //"Failed To Get User Information For User "
        }
    
        public void OnDataChange(DataSnapshot snapshot)
        {
            Dictionary<string, string> Map = new Dictionary<string, string>();
            var items = snapshot.Children?.ToEnumerable<DataSnapshot>(); // using Linq
            foreach(DataSnapshot item in items)
            {
                try
                {
                    Map.Add(item.Key, item.Value.ToString()); // item.value is a Java.Lang.Object
                }
                catch(Exception ex)
                {
                    //"EXCEPTION WITH DICTIONARY MAP"
                }
            }
            User toReturn = new User();
            toReturn.UserID this.ID;
            foreach (var item in Map)
            {
                switch (item.Key)
                {
                    case "email":
                        toReturn.email = item.Value;
                        break;
                    case "lastName":
                        toReturn.lastName = item.Value;
                        break;
                    case "name":
                        toReturn.name = item.Value;
                        break;
                    case "phone":
                        toReturn.phone = item.Value;
                        break;                        
                }
            }
        }
    }
    

    更新 我想提一下,我在写这篇文章时遗漏了一些东西,那就是 Firebase.Database NuGet 包与 Gson NuGet 包和 Newtonsoft.Json 库的使用

    如果您决定使用 FIrebase.Database 库,只需知道您将与 Java.Lang 和 Java.Util 库密切合作。像 Java.Lang.Object 这样的对象编写反序列化数据所需的代码可能非常困难且耗时,但不要担心 Gson 就在这里!

    如果你允许,Gson 包可以为你的类反序列化减轻大量工作,如果你允许的话。 Gson 是一个库,可让您执行 Java.Lang.Obj 到 json 字符串反序列化。我知道这看起来很奇怪,把一个物体递给它一个字符串,我知道这听起来违反直觉,但请耐心等待。

    这里是一个例子,说明如何使用 Gson 库处理cordas 中的对象问题。

     public static void Get_User(User user, FirebaseApp app)
        {
            FirebaseDatabase database = FirebaseDatabase.GetInstance(app);
            DatabaseReference reference = database.GetReference($"Users/{user.UserID}");
            reference.AddListenerForSingleValueEvent(new User_DataValue(user, app));
            //$"Trying to make call for user orders Users/{user.UserID}");
        }
    
    class User_DataValue : Java.Lang.Object, IValueEventListener
        {
            private User User;
            private FirebaseApp app;
            public UserOrderID_Init_DataValue(User user, FirebaseApp app)
            {
                this.User = user;
                this.app = app;
            }
            public void OnCancelled(DatabaseError error)
            {
                //$"Failed To Get User Orders {error.Message}");
            }
            public void OnDataChange(DataSnapshot snapshot)
            {
                //"Data received for user orders");
                var gson = new GsonBuilder().SetPrettyPrinting().Create();
    
                var json = gson.ToJson(snapshot.Value); // Gson extention method obj -> string
                Formatted_Output("Data received for user order json ", json);
    
                User user = JsonConvert.DeserializeObject<User>(json); //Newtonsoft.Json extention method string -> object
    
               //now the user is a fully populated object with very little work
            }
    

    对于将来可能遇到此问题的任何人,我希望这会有所帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-21
      • 2017-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多