xamarin.forms join query on azure sql database - sql

I have created a Xamarin.Forms app in Visual Studio that connects to an Azure SQL Database via an Azure Mobile App. So far everything is working fine - I can do CRUD operations on the database from my Xamarin App.
However I have not yet been able to perform an inner join query on two or more tables.
I have created one such query in a View on the Database, and it works ok on the server, but my problem is that I do not know how to connect to this View from the Xamarin.Forms app.
I would really appreciate any help :-)
Thank you!
XAMARIN.FORMS SERVICE CLASS FOR A GENERIC AZURE TABLE:
public class service<T> : serviceBase<T> where T : irlm.azure.models.modelBase
{
public async Task<ObservableCollection<T>> get()
{
var items = await table.ToEnumerableAsync();
return new ObservableCollection<T>(items);
}
public async Task<T> update(T item)
{
if (item.Id == null)
await table.InsertAsync(item);
else
await table.UpdateAsync(item);
return item;
}
public async Task delete(T item)
{
await table.DeleteAsync(item);
}
}
public abstract class serviceBase<T>
{
MobileServiceClient dc;
public IMobileServiceTable<T> table;
public serviceBase()
{
dc = new MobileServiceClient(irlm.constants.appUrl);
table = dc.GetTable<T>();
}
}
XAMARIN.FORMS MODEL EXAMPLE
public abstract class modelBase
{
public string Id { get; set; }
}
public class golfClub : modelBase
{
public string name { get; set; }
}
public class golfCourse : modelBase
{
public string idClub { get; set; }
public string name { get; set; }
}
XAMARIN.FORMS VIEWMODEL:
public class viewModel<T> : INotifyPropertyChanged
{
private ObservableCollection<T> _items = new ObservableCollection<T>();
public ObservableCollection<T> items
{
get { return _items; }
set
{
_items = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
CONTENT PAGE:
irlm.azure.viewModels.viewModel<irlm.azure.models.golfClub> golfClubs = new azure.viewModels.viewModel<azure.models.golfClub>();
irlm.azure.services.service<irlm.azure.models.golfClub> dc = new azure.services.service<azure.models.golfClub>();
ListView list;
Entry txt = new Entry();
private async void BtnAdd_Clicked(object sender, EventArgs e)
{
var golfCourse = await dc.update(new irlm.azure.models.golfClub { name = txt.Text });
golfClubs.items.Add(golfCourse);
}
private async void BtnUpdate_Clicked(object sender, EventArgs e)
{
var index = golfClubs.items.IndexOf(list.SelectedItem as irlm.azure.models.golfClub);
var item = (irlm.azure.models.golfClub)list.SelectedItem;
item.name = txt.Text;
await dc.update(item);
golfClubs.items[index] = item;
}
private async void BtnRemove_Clicked(object sender, EventArgs e)
{
var item = (irlm.azure.models.golfClub)list.SelectedItem;
await dc.delete(item);
golfClubs.items.Remove((irlm.azure.models.golfClub)list.SelectedItem);
txt.Text = "";
}

Related

getting 400 error on webapi call blazorserver

i am trying to setup a blazor server app, calling a webapi.
I keep getting a 400 error returned, when I call the API.
I have 3 Projects, projectserver and projectapi. projectserver is where the Blazor app sits and Project API is where the API sits.
I don't know if the apicall can find the API as it does not hit any breakpoints in the API section, I am totally confused, as if it cannot find the API then it should return a 404 or other error and not 400 ?
thank you for your efforts.
this is my code,
Projectserver, this is where I post the Register Model to the API
public string message { get; set; }
public RegisterModel r = new RegisterModel();
private async Task Create(MouseEventArgs e)
{
var json = Newtonsoft.Json.JsonConvert.SerializeObject(r);
var client = clientfactory.CreateClient("ServerApi");
var result = await client.PostAsJsonAsync("/Account/Register",json); // check the Startup file and check base address for the Full route.
message = result.StatusCode.ToString();
}
}
the ClientFactory returns the base address of what is defined in startup.cs
services.AddHttpClient("ServerApi", client => client.BaseAddress = new Uri("https://localhost:44302/"));
the API is Projectserver and defined as follows.
[Route("[controller]")]
[ApiController]
public class AccountContoller : ControllerBase
{
private readonly ApplicationDbContext _context;
private readonly SecurityOptions _securityOptions;
private readonly JwtIssuerOptions _jwtOptions;
// GET: api/<Account>
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/<Account>/5
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
// POST api/<Account>
[HttpPost]
public void Post([FromBody] string value)
{
}
// POST api/<Account>
[HttpPost("Register")]
public async Task<ActionResult<RegisterResult>> Register(RegisterModel model)
{
RegisterResult r = new RegisterResult();
var Exisits = await _context.Users.Where(r => r.EmailAddress == model.Email).FirstOrDefaultAsync();
if(Exisits != null)
{
r.Sucsess = false;
r.ErrorMessage = "Email - Already Exisits";
return r;
}
else
{
try
{
User newuser = new User();
newuser.CreatedDateTime = DateTime.UtcNow;
newuser.UserID = Guid.NewGuid();
newuser.MobileNumber = model.MobileNumber;
newuser.Password = model.Password;
newuser.FirstName = model.FirstName;
newuser.Surname = model.LastName;
_context.Users.Add(newuser);
await _context.SaveChangesAsync();
r.Sucsess = true;
return r;
}
catch(Exception e)
{
r.Sucsess = false;
r.ErrorMessage = e.ToString();
return r;
}
}
}
the Model classes are defined as Serializable
[Serializable]
public class RegisterResult
{
public bool Sucsess { get; set; }
public string ErrorMessage { get; set; }
}
[Serializable]
public class RegisterModel
{
public string UserName { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string RoleID { get; set; }
public string EntityID { get; set; }
public string MobileNumber { get; set; }
}
Can you please modify your code as below and give it a try:-
var serializedBody = JsonConvert.SerializeObject(r);
var jsonRequestBodyContent = new StringContent(serializedBody, Encoding.UTF8,"application/json");
var client = clientfactory.CreateClient("ServerApi");
var result = await client.PostAsync("/Account/Register",jsonRequestBodyContent);

Cosmos DB update fails Unable to cast Guid to string

Tried to update a Cosmos DB record in ASP.NET core 3.1. But the update fails with the following message: "Unable to cast object of type 'System.Func'2[Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry,System.Guid]' to type 'System.Func'2[Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry,System.String]'
The error occurs on the saveCangesAsync();
Simplified, the code looks like:
// The service
public async Task<Todo> UpdateAsync(Todo entity)
{
var response = ctx.Todos.Update(entity);
await ctx.SaveChangesAsync(); // Error here
return response.Entity;
}
// The entity Todo
public class Todo
{
public Guid id { get; set; }
[Required(ErrorMessage = "Description is required")]
public string description { get; set; }
...
}
// The context
public class TodoDbContext : DbContext
{
public DbSet<Todo> Todos { get; set; }
public TodoDbContext(DbContextOptions<TodoDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultContainer("Todos");
}
}
// The controller
[HttpPut]
public async Task<IActionResult> Put(Todo todo)
{
try
{
if (ModelState.IsValid)
{
Todo td = await service.GetAsync(todo.id.ToString());
if (td != null)
{
td.description = todo.description;
var response = await service.UpdateAsync(td);
return Ok(response);
}
return BadRequest("Not found.");
}
else
{
return BadRequest(ModelState);
}
}
catch (Exception ex)
{
return BadRequest(ex.Message); // Exception here
}
}
I can insert, read, but not update, so following code runs fine (with a Guid as well)
public async Task<Todo> CreateAsync(Todo entity)
{
entity.id = Guid.NewGuid();
var response = await ctx.Todos.AddAsync(entity);
await ctx.SaveChangesAsync();
return response.Entity;
}
Thanks for any help!
Don't use "id", that will collide with the automatically generated id. Use another property or use "Id" (with a capital I) in stead, to solve the problem.
Is there any reason you're using Guid as your id type? In your Todo class you could write it like so:
public class Todo
{
[JsonProperty("id")
public string Id { get; set; }
[JsonProperty("description")
[Required(ErrorMessage = "Description is required")]
public string description { get; set; }
}
I'm assuming that you're using v3 of the Cosmos DB SDK. You would then just use Guid.NewGuid().ToString() to set the id as a Guid (but as a string type).

Invalid column name 'EmailAddress' when using generic repository, but works fine with context

Getting the mentioned error when trying to do a GetAll on accounts. It works fine if I go directly to the dbcontext, but gives me the error if I try to work with the repo. I have about 20 others that use just the generic repo and are working great. Because I have additional actions for Accounts, I have created its own repository that implements the generic. I also have several others that work like this and have no problem. The problem is specific to the accounts.
Database of course does have the EmailAddress column, since I can return it if I use dbcontext from the controller instead of the repo.
Any help would be much appreciated.
AccountsController:
public class AccountsController : ControllerBase
{
private readonly AccountRepository _repo;
public AccountsController(DatabaseContext context)
{
_repo = new AccountRepository(context);
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Account>>> GetAccount()
{
// return _context.Account.ToListAsync(); works fine if _context is defined
var accounts = await _repo.GetAll();
if (accounts == null)
return NoContent();
return Ok(accounts); // Gives invalid column error
}
[HttpGet("getaccount")]
public async Task<ActionResult<Account>> GetCurrentAccount()
{
var account = await _repo.GetCurrentAccount(HttpContext.User.Identity.Name);
if (account == null)
{
return NotFound();
}
return account; // Works fine
}
}
Account:
public partial class Account
{
public string Name { get; set; }
public string RefId { get; set; }
public string Position { get; set; }
public bool IsActive { get; set; }
public string EmailAddress { get; set; }
[Key]
public string UserId { get; set; }
}
IAccountRepository:
public interface IAccountRepository : IRepository<Account>
{
Task<Account> GetCurrentAccount(string emailAddress);
}
AccountRepository:
public class AccountRepository : Repository<Account>, IAccountRepository
{
private DatabaseContext _context;
public AccountRepository(DatabaseContext context)
{
_context = context;
}
public async Task<Account> GetCurrentAccount(string emailAddress)
{
var account = await _context.Account
.Where(a => a.EmailAddress == emailAddress)
.FirstOrDefaultAsync();
return account; // this works just fine, and returns with EmailAddress
}
}
IRepository (generic):
public interface IRepository<T>
{
Task<IEnumerable<T>> GetAll();
Task<T> GetById(object id);
void Add(T entity);
void Update(T entity);
void Delete(T entity);
Task<bool> Save();
}
Repository (generic):
public class Repository<T> : IRepository<T> where T : class
{
private DatabaseContext _context;
public Repository()
{
_context = new DatabaseContext();
}
public Repository(DatabaseContext context)
{
_context = context;
}
public void Add(T obj)
{
_context.Set<T>().Add(obj);
}
public void Delete(T entity)
{
_context.Set<T>().Remove(entity);
}
public async Task<IEnumerable<T>> GetAll()
{
return await _context.Set<T>().ToListAsync();
}
public async Task<T> GetById(object id)
{
return await _context.Set<T>().FindAsync(id);
}
public void Update(T obj)
{
_context.Set<T>().Update(obj);
}
public async Task<bool> Save()
{
try
{
await _context.SaveChangesAsync();
}
catch (Exception)
{
return false;
}
return true;
}
}
EDIT
I should mention that EmailAddress was added to the database via EF migration.

XamarinForms Exception

I created a search bar with database connection. When i run it. It get an exception. i use a database that was created before.
Model class entries
public class entries
{
public entries()
{
}
public entries(string word)
{
this.word = word;
}
public entries(string word, string wordtype, string definition)
{
this.word = word;
this.wordtype = wordtype;
this.definition = definition;
}
public string word
{ get; set; }
public string wordtype
{ get; set; }
public string definition
{ get; set; }
public List<string> GetWord { get; set; }
}
Class DatabaseManager:
public class DatabaseManager
{
SQLiteConnection dbConnection;
public DatabaseManager()
{
dbConnection = DependencyService.Get<ISQLite>().GetConnection();
}
public List<string> GetWord()
{
return dbConnection.Query<string>("Select word From [entries]").ToList();
}
}
MainPage.xaml.cs:
DatabaseManager dbManager = new DatabaseManager();
private void MySearchBar_SearchButtonPressed(object sender, EventArgs e)
{
}
private void MySearchBar_TextChanged(object sender, TextChangedEventArgs e)
{
var keyword = MySearchBar.Text;
if(keyword.Length >= 1) {
var suggestions = dbManager.GetWord().Where(c => c.ToLower().Contains(keyword.ToLower()));
SuggestionListView.ItemsSource = suggestions;
SuggestionListView.IsVisible = true;
}
else
{
SuggestionListView.IsVisible = false;
}
}
This is Exception:
System.MissingMethodException: Constructor on type 'System.String' not
found.
Please Help. Thank you so much.
You might have created an Entity for the “entries” table, say for example it is,
[Table (“entries”)]
public class Entries
{
…
[Column (“word”)]
public string Word;
…
}
then change the line
dbConnection.Query<string>("Select word From [entries]").ToList();
to
dbConnection.Table<Entries>().Select(x => x.Word).ToList();
This will remove the requirement of creating one additional class as Sushi said in above comment.
Moreover, following line will throw a NullReferenceException at c.ToLower(), if any of the word contains Null into the table.
dbManager.GetWord().Where(c => c.ToLower().Contains(keyword.ToLower()));
So to get rid of this, select results which has not null values like,
dbConnection.Table<Entries>().Where(x => x.Word != null).Select(x => x.Word).ToList();

Windows Phone 8.1 RT view not updating (MVVM)

I'm designing a profile page for users where they can edit their personal info. I'm using a PersonViewModel (which contains the current signed in person) to display the current info about the User. The fields to edit the user's info are bound to a validation model. After pressing the 'execute changes' button and I get a response of the server (HTTPStatusCode Ok + the altered user object), I alter the fields of the existing object according to the changes. Then I used setter injection to update my PersonViewModel... When debugging, I can see that my objects are all up-to-date but my view is still displaying the old info... What am I doing wrong?`
This is the code that get's executed when I press the button to execute my changes:
private async void ChangeInfoButton(object sender, RoutedEventArgs e)
{
User user;
List<ErrorInfo> errors;
if (_profileInformationValidationModel.TryGetUser(out user, out errors))
{
var response = await Session.Instance.DataProvider.UpdaterUserInfo(user);
if (response.IsSuccess)
{
/*SignedInUserInfo = AlteredUserInfo*/
Session.Instance.User.Information = user.Information;
_personViewModel.SetPerson(user.Information);
var d1 = new MessageDialog("Uw gegevens werden succesvol gewijzigd.");
d1.ShowAsync();
AnnulInfoButton(sender, e);
}
`
And this is the PersonViewModel:
public class PersonViewModel
{
private Person _person;
public void SetPerson(Person p)
{
_person = p;
}
public PersonViewModel(Person person)
{
_person = person;
}
public string Street
{
get { return _person.Street; }
}
public string HouseNumber
{
get { return _person.HouseNumber; }
}
public string Bus
{
get { return _person.Bus; }
}
public string Email
{
get { return _person.Email; }
}
Your view model should implement the INotifyPropertyChanged interface.
Look into using a framework like MVVM Light which does most of this work for you.
You can add it to your project using NuGet.
This is how your model and view-model should look:
public class Person
{
public string Street { get; set; }
public string HouseNumber { get; set; }
public string Bus { get; set; }
public string Email { get; set; }
}
public class PersonViewModel : System.ComponentModel.INotifyPropertyChanged
{
private Person _person;
public void SetPerson(Person person)
{
_person = person;
Street = person.Street;
HouseNumber = person.HouseNumber;
Bus = person.Bus;
Email = person.Email;
}
public PersonViewModel(Person person)
{
SetPerson(person);
}
#region Street (INotifyPropertyChanged Property)
private string _street;
public string Street
{
get { return _street; }
set
{
if (_street != value)
{
_street = value;
RaisePropertyChanged("Street");
}
}
}
#endregion
#region HouseNumber (INotifyPropertyChanged Property)
private string _houseNumber;
public string HouseNumber
{
get { return _houseNumber; }
set
{
if (_houseNumber != value)
{
_houseNumber = value;
RaisePropertyChanged("HouseNumber");
}
}
}
#endregion
#region Bus (INotifyPropertyChanged Property)
private string _bus;
public string Bus
{
get { return _bus; }
set
{
if (_bus != value)
{
_bus = value;
RaisePropertyChanged("Bus");
}
}
}
#endregion
#region Email (INotifyPropertyChanged Property)
private string _email;
public string Email
{
get { return _email; }
set
{
if (_email != value)
{
_email = value;
RaisePropertyChanged("Email");
}
}
}
#endregion
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string p)
{
var propertyChanged = PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(p));
}
}
}