Filter result from firebase ObservableCollection - firebase

I am trying to filter records from FirebaseDB in my Xamarin app.
Following code returns all records from DB:
internal ObservableCollection<MessageModel> GetMessages(Guid messageId)
{
var result = (firebase).Child("Messages").AsObservable<MessageModel>().AsObservableCollection();
return result;
}
But when I apply Where it returns 0 records event that se that I have records in DB that match MessageId
internal ObservableCollection<MessageModel> GetMessages(Guid messageId)
{
var result = (firebase).Child("Messages").AsObservable<MessageModel>().AsObservableCollection().Where(s => s.Id == messageId); ;
return new ObservableCollection<MessageModel>(result);
}

I suggest you can use the following code to query data from firebase.
public async Task<List<Person>> GetAllPersons()
{
return (await firebase
.Child("Persons")
.OnceAsync<Person>()).Select(item => new Person
{
Name = item.Object.Name,
PersonId = item.Object.PersonId
}).ToList();
}
public async Task<Person> GetPerson(int personId)
{
var allPersons = await GetAllPersons();
await firebase
.Child("Persons")
.OnceAsync<Person>();
return allPersons.Where(a => a.PersonId == personId).FirstOrDefault();
}
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
}

Related

How do I prevent a duplicate entry for a Create/Edit Functionality in ASP.NET Core w/ EF?

I am trying to prevent a user from creating a form with a FirstName, LastName, and DOB that match an entry in the database and editing a form to match an existing entry. If you could also lead me to how I can show an error when this happens, that would be awesome.
My Model:
public class MRegForm
{
public int MRegFormId { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; } = string.Empty;
[Display(Name = "Last Name")]
public string LastName { get; set; } = string.Empty;
public DateTime DOB { get; set; }
[I tried Index attribute. It did not work for me. I was able to create new duplicate forms with no issues.
[Index(nameof(FirstName), nameof(LastName), nameof(DOB), IsUnique = true)]
public class MRegForm
{
I also tried this. Same thing.
protected override void OnModelCreating(ModelBuilder modelbuilder)
{
base.OnModelCreating(modelbuilder);
modelbuilder.Entity<MRegForm>()
.HasIndex(x => new { x.FirstName, x.LastName, x.DOB})
.IsUnique();
}
public DbSet<MRegForm> MRegForm { get; set; } = default!;
I think that there is maybe a way to prevent this in the OnPostAsync()
This is my create OnPostAsync():
public async Task<IActionResult> OnPostAsync()
{
MRegForm.CreatorId = UserManager.GetUserId(User);
var isAuthorized = await AuthorizationService.AuthorizeAsync(User, MRegForm, RegFormOperations.Create);
if (isAuthorized.Succeeded == false)
return Forbid();
Context.MRegForm.Add(MRegForm);
await Context.SaveChangesAsync();
return RedirectToPage("./Index");
}
This is my Edit OnPostAsync():
public async Task<IActionResult> OnPostAsync(int id)
{
var mRegForm = await Context.MRegForm.AsNoTracking().SingleOrDefaultAsync(m => m.MRegFormId == id);
if (mRegForm == null)
return NotFound();
MRegForm.CreatorId = mRegForm.CreatorId;
var isAuthorized = await AuthorizationService.AuthorizeAsync(User, MRegForm, RegFormOperations.Update);
if (isAuthorized.Succeeded == false)
return Forbid();
MRegForm.Status = mRegForm.Status; // the Status is the current Status - Do Not Reset
Context.Attach(MRegForm).State = EntityState.Modified;
try
{
await Context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MRegFormExists(MRegForm.MRegFormId))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool MRegFormExists(int id)
{
return (Context.MRegForm?.Any(e => e.MRegFormId == id)).GetValueOrDefault();
}
}
You can try to download the entity from the database if exists and make changes to it or creating new one if not exist.
Your clients can always make new MRegForm in the form, but you add or update in the back and. Bether option will be to pass the existing MRegForm to the form and the client see and change all props he need.
public async Task AddOrUpdate(MRegForm input)
{
var mRegForm = await Context.MRegForm
.FirstOrDefaltAsync(x => x.FirstName == input.FirstName && x.LastName == input.LastName && x.DOB == input.YourDate);
if(mRegForm != null)
{
//Make changes on mRegForm
mRegForm.SomeProp = input.SomeProp,
...
}
else
{
var newMRegForm = new MRegForm
{
//Set all props you need
}
await this.Context.AddAsync(newMRegForm );
}
await this.Context.SaveCangesAsync();
}

Syncfusion TreeView doesnt show data

I have a list that matches the requirements that I get through the request from js.
Data from the request comes filled in, but the list is not displayed
< ejs-treeview id="treedata" created="created">
< e-treeview-fields dataSource="#Model.Items" id="LevelCode" parentId="ParentLevelCode" text="Name" hasChildren="HasChild"></e-treeview-fields>
< /ejs-treeview>
function created()
{
getCategories();
}
function getCategories() {
let treedata = document.getElementById('treedata').ej2_instances[0];
let request = new ej.base.Ajax(`/Category/GetAll`, 'GET');
request.send();
request.onSuccess = data => {
if (treedata.element !== undefined) {
let final = JSON.parse(data);
treedata.fields.dataSource = final.Categories;
treedata.dataBind();
treedata.refresh();
}
};
}
public class GetAllCategoriesHandlerResponseItem
{
public string Id { get; set; }
public string Name { get; set; }
public bool HasChild { get; set; }
public string LevelCode { get; set; }
public string ParentLevelCode { get; set; }
}
In TreeView component, the fields property has been provided to set or get the data source and other data-related information. You can use this property to dynamically change the TreeView component data source. But you need to specify the properties in its predefined structure to update the TreeView data source.
Check the below code snippet.
function getCategories() {
let treedata = document.getElementById('treedata').ej2_instances[0];
let request = new ej.base.Ajax(`/Category/GetAll`, 'GET');
request.send();
request.onSuccess = data => {
if (treedata.element !== undefined) {
let final = JSON.parse(data);
treedata.fields = {datasource: final.Categories, id:"LevelCode", parentId:"ParentLevelCode", text:"Name", hasChildren:"HasChild" };
treedata.dataBind();
treedata.refresh();
}
};
}
You can refer to the below link to know about the details.
https://www.syncfusion.com/kb/10135/how-to-refresh-the-data-in-ej2-treeview

try to send a viewmodel to view

I have a asp mvc project :
Model:
public class TeamDto
{
public int TenantId { get; set; }
public string Name { get; set; }
public List<UserListDto> Users { get; set; }
}
public class AddTeamViewModel
{
public TeamDto Team { get; set; }
public List<UserListDto> AllUsers { get; set; }
}
Controller:
public async Task<IActionResult> AddOrEditTeam(int id = 0)
{
var users = await _userAppService.GetAllUsers();
var view = new AddTeamViewModel { Team = new TeamDto(), AllUsers = users.ToList() };
if (id == 0) return View(view);
var team = await _teamAppService.GetTeamById(id);
return View(new AddTeamViewModel { AllUsers = users.ToList() , Team = team });
}
View:
<h4 class="m-portlet__head-caption">#(Model.Team.Id > 0 ? "Edit Team" : "Add Team")</h4>
I can not undrestand why I get this error:
An unhandled exception occurred while processing the request.
NullReferenceException: Object reference not set to an instance of an object.
AspNetCore.Areas_App_Views_Team_AddOrEditTeam.b__22_1()
It seems you are posting the value and then trying to send the viewmodel to a view. In this case, try redirecting to action instead of showing the View.
public async Task<IActionResult> AddOrEditTeam(int id = 0)
{
var users = await _userAppService.GetAllUsers();
var view = new AddTeamViewModel { Team = new TeamDto(), AllUsers = users.ToList() };
if (id == 0) return RedirectToAction("YourViewName",view);
var team = await _teamAppService.GetTeamById(id);
AddTeamViewModel teams = new AddTeamViewModel{
AllUsers = users.ToList(),
Team = team
};
return RedirectToAction("YourViewName", teams);
}
This will solve your object reference issue.

FindOneAndUpdateAsync Intermittently Returning Null

I am using MongoDB.Driver for .NET Core 3.1 and running into an issue were records are not being saved properly. They are intermittently coming back as null when calling FindOneAndUpdateAsync. I have a script that calls my below code 100 times. Out of those 100, 1-5 fail in the last method, SetChildFavoritesAsync. The results came back as null. Any suggestions on what I am doing wrong?
Example Calls
var id = 1;
var childName = "test";
var collectionEntry = await FindByIdOrCreateAsync(id);
collectionEntry.Children = new List<MyCollection.ChildClass>{
new MyCollection.ChildClass{
Name = childName,
Favorites = new List<MyCollection.ChildClass.Favorite>()
}
};
await FindByIdAndUpdateChildrenAsync(collectionEntry.Id, collectionEntry.Children);
var favorites = new List<MyCollection.ChildClass.Favorite>{
Name = "testFavorite"
};
var resultsOfSet = await SetChildFavoritesAsync(id, name, favorites)
//do stuff with resultsOfSet
Example Model
public class MyCollection
{
[MongoDB.Bson.Serialization.Attributes.BsonRepresentation(BsonType.ObjectId)]
[MongoDB.Bson.Serialization.Attributes.BsonId]
public string _Id { get; set; }
[MongoDB.Bson.Serialization.Attributes.BsonRequired]
public int Id { get; set; }
public List<ChildClass> Children { get; set; }
public class ChildClass
{
public string Name { get; set; }
public List<Favorite> Favorites { get; set; }
public class Favorite
{
public string Name { get; set; }
}
}
}
Example Methods
public async Task<MyCollection> FindByIdOrCreateAsync(int id)
{
var filter = Builders<MyCollection>.Filter.Eq(mc => mc.Id, id);
var update = Builders<MyCollection>.Update
.Set(mc => mc.Id, id)
.SetOnInsert(mc => mc.Children, new List<MyCollection.ChildClass>());
var options = new FindOneAndUpdateOptions<MyCollection> { ReturnDocument = ReturnDocument.After, IsUpsert = true };
return await _database.GetCollection<MyCollection>("MyCollectionName").FindOneAndUpdateAsync(filter, update, options);
}
public async Task<MyCollection> FindByIdAndUpdateChildrenAsync(int collectionId, List<MyCollection.ChildClass> children)
{
var filter = Builders<MyCollection>.Filter.Eq(mc => mc.Id, collectionId);
var update = Builders<MyCollection>.Update.Set(mc => mc.Children, children);
var options = new FindOneAndUpdateOptions<MyCollection> { ReturnDocument = ReturnDocument.After, IsUpsert = false };
return await _database.GetCollection<MyCollection>("MyCollectionName").FindOneAndUpdateAsync(filter, update, options);
}
public async Task<MyCollection> SetChildFavoritesAsync(int collectionId, string childName, List<MyCollection.ChildClass.Favorite> favorites)
{
var filter = Builders<MyCollection>.Filter.Eq(mc => mc.Id, collectionId);
filter &= Builders<MyCollection>.Filter.Eq("children.name", childName);
var update = Builders<MyCollection>.Update.Set("children.$.favorites", favorites);
var options = new FindOneAndUpdateOptions<MyCollection> { ReturnDocument = ReturnDocument.After };
var results = await _database.GetCollection<MyCollection>("MyCollectionName").FindOneAndUpdateAsync(filter, update, options);
if (results == null)
{
_log.Error($"Child Favorites didn't save: collectionId:{collectionId}, childName:{childName}");
}
else
{
_log.Debug($"Child Favorites: collectionId:{collectionId}, childName:{childName}, favorites:{Newtonsoft.Json.JsonConvert.SerializeObject(results)}");
}
return results;
}
Appears to be an issue with communication to the database. I added some retry logic, which solved the issue.

How to store unique class instances in SQLite?

I'm trying to store some information as a class instance in a SQLite table. The instances need to be unique in their DateTime property. I'm completely new to database programming, and I don't really understand how use SQLite in Xamarin. As new instances are created they need to update the existing instances in the table if they match in their DateTime property.
SQLiteAsyncConnection connection = new SQLiteAsyncConnection(App.FilePath);
await connection.CreateTableAsync<ModulInformationData>();
ModulInformationData data = new ModulInformationData();
data.InitModulInformation(modul);
int rows = 0;
try
{
rows = await connection.UpdateAsync(data);
}catch(Exception e)
{
Console.WriteLine("SQL Update failed " + e.Message);
}
Console.WriteLine("rows updated: " + rows);
if (rows == 0)
{
Console.WriteLine("before insert");
try
{
int key1 = await connection.InsertAsync(data);
Console.WriteLine("after insert: " + key1);
}catch (Exception e)
{
Console.WriteLine("SQL insert failed " + e.Message);
}
}
The ModulInformationData class
public class ModulInformationData
{
[PrimaryKey,AutoIncrement]
public int Id { get; set; }
[Unique]
public DateTime tidspunkt { get; set; }
other properties...
At the moment, I'm catching an error when inserting, but the message only says 'Constraint'. What can I do to make this work?
Do you want to achieve the result like this GIF。
First of all, you can create a class for the database CRUD.
public class NoteDatabase
{
readonly SQLiteAsyncConnection _database;
public NoteDatabase(string dbPath)
{
_database = new SQLiteAsyncConnection(dbPath);
_database.CreateTableAsync<Note>().Wait();
}
public Task<List<Note>> GetNotesAsync()
{
return _database.Table<Note>().ToListAsync();
}
public Task<Note> GetNoteAsync(int id)
{
return _database.Table<Note>()
.Where(i => i.ID == id)
.FirstOrDefaultAsync();
}
public Task<int> SaveNoteAsync(Note note)
{
if (note.ID != 0)
{
return _database.UpdateAsync(note);
}
else
{
return _database.InsertAsync(note);
}
}
public Task<int> DeleteNoteAsync(Note note)
{
return _database.DeleteAsync(note);
}
}
Then there is model class.
public class Note
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Text { get; set; }
[Unique]
public DateTime Date { get; set; }
public string Gender { get; set; }
}
If we want to add or update the data to the database, firstly, we should update the data to the instance, then we could just save this instance to the database like following save click event.
async void OnSaveButtonClicked(object sender, EventArgs e)
{
var note = (Note)BindingContext;
note.Date = DateTime.UtcNow;
note.Gender = (string)myPicker.SelectedItem;
await App.Database.SaveNoteAsync(note);
await Navigation.PopAsync();
}
Here is my demo. you can download it and refer to it.
https://github.com/851265601/databaseDemo

Resources