Xamarin.Forms: Cannot connect to database - sql

I have this database structure:
public class QRDatabase
{
readonly SQLiteAsyncConnection _database;
public QRDatabase(string dbPath)
{
_database = new SQLiteAsyncConnection(dbPath);
_database.CreateTableAsync<db_QRCODE_Type>().Wait();
}
public Task<List<db_QRCODE_Type>> GetQRCode()
{
return _database.Table<db_QRCODE_Type>().ToListAsync();
}
public Task<int> SaveQRCode(db_QRCODE_Type note)
{
if (note.ID != 0)
{
return _database.UpdateAsync(note);
}
else
{
return _database.InsertAsync(note);
}
}
public Task<int> DelteQRCode(db_QRCODE_Type note)
{
return _database.DeleteAsync(note);
}
}
This uses this type:
public class db_QRCODE_Type
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; } // Identificator of column
public string firstName { get; set; } // firstname
public string lastName { get; set; } // firstname
public byte[] qrBytes { get; set; } //qr code in bytes
}
Then, in the class where I need the DB I am doing this from the tutorial here:
https://learn.microsoft.com/de-de/xamarin/get-started/quickstarts/database?pivots=windows
static QRDatabase database;
static string nameOfDB = "01db_qrs_q2go.db3";
public static QRDatabase Database
{
get
{
if (database == null)
{
database = new QRDatabase(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), nameOfDB));
}
return database;
}
}
However, I am not quite sure how this works since I am never calling "Database" even though this is where the database is supposed to be initiliased.
Now, when I try to write to the database:
db_QRCODE_Type entry = new db_QRCODE_Type();
entry.firstName = entry_firstname.Text;
entry.lastName = entry_lastname.Text;
entry.qrBytes = qrCodeBytes;
try
{
await database.SaveQRCode(entry);
}
catch
{
DependencyService.Get<IMessage>().LongAlert("Etwas hat nicht funktioniert, bitte versuche es noch einmal. Fehlercode: DB_665h");
}
It fails saying it is not set reference to an instance and goes into the catch block. I am doing everything as in the tutorial. Why is this happening?
Thank you!

Related

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).

Retrieve values from SQL database - EF

I'm trying to figure out how to pull values from a SQL database and display this in a razor view.
I have the following class using Entity Framework (I believe)
public class EventLog
{
[Key]
public int Id { get; set; }
public int EventId { get; set; }
public int MaxDelegates { get; set; }
public string Code { get; set; }
public DateTime End { get; set; }
public string Title { get; set; }
}
And I want to map title to DBTitle in the following model:
public class CourseDetailVM : CourseDetailSummaryVM
{
public EventLog DBTitle { get; set; }
}
I then want to see this in the following view:
#using TSW.Web.Helpers
#model TSW.Web.ViewModels.CourseDetailVM
#{
Layout = "~/Views/_Master.cshtml";
}
#Model.DBTitle.Title;
I have the following controller already in place (sorry for the length I plan to reduce this down):
public class CourseDetailController : BaseRenderController<CourseDetailPageDT>
{
private readonly ISitePageFactory _pageFactory = null;
private readonly IEventService _eventService = null;
public CourseDetailController(IEventService eventService, ISitePageFactory pageFactory)
{
_pageFactory = pageFactory;
_eventService = eventService;
}
public async Task<ActionResult> CourseDetail()
{
var homepage = _pageFactory.GetCurrentHomepage();
var model = Mapper.Map<CourseDetailVM>(CurrentContent);
model.Email = homepage.ContactEmail;
model.PhoneNumber = homepage.HeaderPhoneNumber;
model.InnerPageHeader.ShowHeading = true;
model.InnerPageHeader.Title = model.PageTitle;
if (model.Categories.Count == 1)
{
var categoryTagId = model.Categories.First().Id;
var contentTypeAlias = DocumentTypeHelper.GetDocumentTypeAlias<CourseListingPageDT>();
var courseCategoryPage = Umbraco.TypedContentAtXPath($"//{contentTypeAlias}")
.FirstOrDefault(x => x.GetPropertyValue<int>(Constants.DocumentTypes.CourseListingPage.Category) == categoryTagId);
if (courseCategoryPage != null)
{
model.InnerPageHeader.BackLink = Mapper.Map<LinkItem>(courseCategoryPage.Id);
}
}
try
{
model.Events = await _eventService.GetEventsForCourse(CurrentContent.AdministrateId);
}
catch (Exception ex)
{
model.Events = new StaticPagedList<Event>(Enumerable.Empty<Event>(), 1, 1, 0);
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}
if (CurrentContent.Graphic != 0)
{
model.InnerPageHeader.Graphic = Mapper.Map<CtaItem>(CurrentContent.Graphic);
}
return View(model);
}
}
I've tried every suggestion I can google to add the mapping in the controlling but can't get my head around this simple function of pulling the value from a SQL database into the razor view.
Could anyone help me out?

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));
}
}
}

Trouble Creating Specification Across Entities With NLinq

I am using the Specification pattern, and have a working implementation (taken from the WhoCanHelpMe Codeplex project) for getting data via NLinq, generic repositories and all that goodness.
The root method is:
public IList<Case> GetCasesByUsername(string username)
{
CaseByUserNameSpecification spc = new CaseByUserNameSpecification(username);
return this.caseRepository.FindAll(spc).ToList();
}
The FindAll() method does the following:
public IQueryable<T> FindAll(ILinqSpecification<T, T> specification)
{
return specification.SatisfyingElementsFrom(this.Session.Linq<T>());
}
And, SatisfyingElementsFrom() does this:
public virtual IQueryable<TResult> SatisfyingElementsFrom(IQueryable<T> candidates)
{
if (this.MatchingCriteria != null)
{
return candidates.Where(this.MatchingCriteria).ToList().ConvertAll(this.ResultMap).AsQueryable();
}
return candidates.ToList().ConvertAll(this.ResultMap).AsQueryable();
}
So, for querying cases by CaseNb property of a Case, it's pretty straight-forward. A Specification like the one below works for me and gets the cases I'd want.
public class CaseByCaseNbSpecification : QuerySpecification<User>
{
private string caseNb;
public CaseByCaseNbSpecification(string caseNb)
{
this.caseNb = caseNb;
}
public string UserName
{
get { return this.caseNb; }
}
public override Expression<Func<Case, bool>> MatchingCriteria
{
get { return u => u.CaseNb.Equals(this.caseNb, StringComparison.CurrentCultureIgnoreCase); }
}
}
However, I am at a loss to understand how to do this when crossing multiple entities. What I'd like to have is a Specification that allows me to get Cases by UserName. Basically, in the database, there are three tables and these have been carried into entities. Here's are entities:
Here's the Case class:
public class Case : Entity
{
private ICollection<CaseUser> caseUsers = new HashSet<CaseUser>();
public virtual Patient Patient { get; set; }
public virtual string CaseNb { get; set; }
...
public virtual IEnumerable<CaseUser> CaseUsers { get { return caseUsers; } }
}
Here's the CaseUser:
public class CaseUser : Entity
{
public virtual Case Case { get; set; }
public virtual User User { get; set; }
...
}
And, User:
public class User : Entity
{
private ICollection<CaseUser> caseUsers = new HashSet<CaseUser>();
public virtual Account Account { get; set; }
public virtual string UserName { get; set; }
...
public virtual IEnumerable<CaseUser> CaseUsers { get { return caseUsers; } }
}
How would I write the Expression to get the data across the association table?
I believe your specification implementation should look something like this:
public class CaseByUsernameSpecification : QuerySpecification<Case>
{
private string userName;
public CaseByUsernameSpecification(string userName)
{
this.userName = userName;
}
public string UserName
{
get { return this.userName; }
}
public override Expression<Func<Case, bool>> MatchingCriteria
{
get { return c => c.CaseUsers.Any(cu => cu.User.Username == this.userName); }
}
}