问题
I need to read only one entity from Firebase Realtime Database and convert the result into a C# class matching the structure, but I haven't found a solution clear. Having this tree:
{
"characters" : {
"c1" : {
"Email" : "peter.pan@example.com",
"LastName" : "Pan",
"Name" : "Peter"
},
"c2" : {
"Email" : "harry.potter@example.com",
"LastName" : "Potter",
"Name" : "Harry"
}
}
}
And this C# class:
public class Character
{
public string Email {get; set; }
public string Name { get; set; }
public string LastName { get; set; }
}
I would like to retrieve only one record by email, which I know and it is unique. But, if I do include the NuGet package Xamarin.Firebase.Database there not exists a method or extension method such as OnceSingle<T>() or OnceSingleAsync<T>()
in it:
Character character = await FirebaseDatabase.Instance
.GetReference(CharactersRoot)
.OrderByChild("Email")
.EqualTo("harry.potter@example.com") //Works until here
.OnceSingleAsync<Character>(); //THIS METHOD IS NOT AVAILABLE. It doesn't work.
In the other hand, by including package Xamarin.Forms.FirebaseWrapper, an upgrade of the former Firebase.Xamarin, that supports OnceSingleAsync<T>()
one can code something like this:
FirebaseClient fbClient= new FirebaseClient(Root);
var task = Task<Character>.Run(async () =>
{
return await fbClient.Child(CharactersRoot)
.OrderBy("Email")
.EqualTo("harry.potter@example.com")
.OnceSingleAsync<Character>().ConfigureAwait(false)
});
var character = task.Result;
// do something with character...
But it doesn't work. It raises a System.AggregateException: 'One or more errors occurred. (Response status code does not indicate success: 400 (Bad Request).)'
The following is the only I've managed to make it work, but it is under performant because it retrieves all the collection and performs the search locally.
FirebaseClient fbClient= new FirebaseClient(Root);
var task = Task<Character>.Run(async () =>
{
return await fbClient.Child(CharactersRoot)
.OnceAsync<Character>()
.ConfigureAwait(false);
});
var character = task.Result
.Where(item => item.Object.Email == "harry.potter@example.com")
.Select(itm => itm.Object)
.FirstOrDefault();
if (character != null)
{
//Do something with character
}
Any ideas that can help to clarify my mind to do it simpler and better will be appreciated.
回答1:
I would like to retrieve only one record by email, which I know and it is unique.
What you are looking for is a way to query the database based on certain value(Email). Reading through the Firebase Database Doc, you can find the Filtering Data which explains what you want.
To meet your scenario, what you need to do is:
Sort your children elements based on Email and use EuqalTo() to limit the output data range.
var db = FirebaseDatabase.Instance; var mDatabase = db.GetReference("characters"); Query query = mDatabase.OrderByChild("Email") .EqualTo("harry.potter@example.com");
Create a Child event listener to retrieve the filtered data.
public class MyChildEventListener : Java.Lang.Object, IChildEventListener { public void OnCancelled(DatabaseError error) {} public void OnChildAdded(DataSnapshot snapshot, string previousChildName) { //this method will be triggered //snapshot's key is c2 namly harry potter } public void OnChildChanged(DataSnapshot snapshot, string previousChildName) {} public void OnChildMoved(DataSnapshot snapshot, string previousChildName) {} public void OnChildRemoved(DataSnapshot snapshot) {} }
Register
MyChildEventListener
:query.AddChildEventListener(new MyChildEventListener());
回答2:
public async Task<Character> GetAttendant(string email)
{
return (await firebase
.Child("Character")
.OnceAsync<Character>()).Select(item => new Character
{
EmailAddress = email,
}).FirstOrDefault();
}
//Hope this helps
来源:https://stackoverflow.com/questions/58881101/how-to-retrieve-a-single-record-from-firebase-real-time-database-in-xamarin-andr