我两天前发布了关于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类中添加构造函数,但这没有帮助。
答案 0 :(得分:2)
好的,所以我没有找到解决这个问题的解决方案,也不知道为什么会发生这种情况,但我找到了一个解决方法。我认为它不是理想的解决方案,并且它不能解决现有问题。或许这可能是我不了解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,但我不明白如何创建我的课程,所以我可以通过其他方式获取数据,所以我这样做了。它工作正常。
如果有人有更好的解决方案,我很乐意改变它。干杯
答案 1 :(得分:1)
这应该是评论,但这只是对需要此问题帮助的任何人的补充。
我知道这个答案已经存在了一段时间,但这似乎仍然与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库带给我们。
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
}
对于将来可能遇到此问题的任何人,我希望这会有所帮助