Implement SQLite Xamarin.Forms - Unable to create SQLiteAsyncConnection - c#

I am trying to implement SQLite into my Xamarin.Forms Shared Assets project from this article.
https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/databases/
All appears to be set up correctly tyo my novice eyes, however there seems to be a problem in creating the database connection. It says its Not able to implicitly convert type SQLite.SQLiteAsyncConnection to TechsportiseApp.Data.TechsportiseData
I can't work out why this is. Any ideas?
using System;
using System.Collections.Generic;
using System.Text;
using SQLite;
using Xamarin.Forms;
using static TechsportiseApp.Helpers.GlobalFunctions;
using TechsportiseApp.Models;
using System.Threading.Tasks;
namespace TechsportiseApp.Data
{
class TechsportiseData
{
public TechsportiseData(string dbPath)
{
database = new SQLite.SQLiteAsyncConnection(dbPath);
database.CreateTableAsync<Scan>().Wait();
database.CreateTableAsync<Timing>().Wait();
}
static TechsportiseData database;
public static TechsportiseData Database
{
get
{
if (database == null)
{
database = new TechsportiseData(DependencyService.Get<IFileHelper>().GetLocalFilePath("TechsportiseData.db3"));
}
return database;
}
}
public Task<List<Timing>> GetTimingsAsync()
{
return database.Table<Timing>().ToListAsync();
}
public Task<List<Timing>> GetTimingsNotUploadedAsync()
{
return database.QueryAsync<Timing>("SELECT * FROM [Timing] WHERE [Uploaded] = 0");
}
public Task<Timing> GetTimingAsync(int id)
{
return database.Table<Timing>().Where(i => i.ID == id).FirstOrDefaultAsync();
}
public Task<int> SaveTimingAsync(Timing timing)
{
if (timing.ID != 0)
{
return database.UpdateAsync(timing);
}
else
{
return database.InsertAsync(timing);
}
}
public Task<int> DeleteTimingAsync(Timing timing)
{
return database.DeleteAsync(timing);
}
public Task<int> DeleteAllTimingsAsync()
{
return database.DeleteAllAsync(timing);
}
public Task<List<Scan>> GetScansAsync()
{
return database.Table<Scan>().ToListAsync();
}
public Task<List<Scan>> GetScansNotUploadedAsync()
{
return database.QueryAsync<Timing>("SELECT * FROM [Scan] WHERE [Uploaded] = 0");
}
public Task<Scan> GetScanAsync(int id)
{
return database.Table<Scan>().Where(i => i.ID == id).FirstOrDefaultAsync();
}
public Task<int> SaveScanAsync(Scan scan)
{
if (scan.ID != 0)
{
return database.UpdateAsync(scan);
}
else
{
return database.InsertAsync(scan);
}
}
public Task<int> DeleteScanAsync(Scan scan)
{
return database.DeleteAsync(scan);
}
public Task<int> DeleteAllScanssAsync()
{
return database.DeleteAllAsync(scan);
}
}
}

The first and most obvious thing is this doesn't make sense
static TechsportiseData database;
change it to this
readonly SQLiteAsyncConnection database;

So it turns out the section of code
static TechsportiseData database;
public static TechsportiseData Database
{
get
{
if (database == null)
{
database = new TechsportiseData(DependencyService.Get<IFileHelper>().GetLocalFilePath("TechsportiseData.db3"));
}
return database;
}
}
Needed to be in App.cs which I didn't realize. Seems good now!

Related

How to work with two or more tables (sqlite-net-plc)

Created two tables
public TodoItemDatabase(string dbPath)
{
database = new SQLiteAsyncConnection(dbPath);
database.CreateTableAsync<OneTable>().Wait();
database.CreateTableAsync<OtherTable>().Wait();
}
Created save methods in one file
Only one method works.
public Task<int> SaveItemAsync(ModelOneTable item)
{
if (item.ID != 0)
{
return database.UpdateAsync(item);
}
else {
return database.InsertAsync(item);
}
}
public Task<int> SaveItemAsyncOther(OtherTable item)
{
if (item.ID != 0)
{
return database.UpdateAsync(item);
}
else {
return database.InsertAsync(item);
}
}
Two methods should work.
doing like here https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/databases/
Edit your method like so:
public TodoItemDatabase(string dbPath)
{
CreateDb(dbPath);
}
public async void CreateDb(string dbPath)
{
database = new SQLiteAsyncConnection(dbPath);
// wait until first query completed
await database.CreateTableAsync<OneTable>();
// then execute second create query
await database.CreateTableAsync<OtherTable>();
}

How to convert blocking IEnumerable to Akka actor

I would like to convert a blocking IEnumerable (possibly infinite) into messages sent to an Actor. What is the best way to do this? I am currently attempting to create a Task within an actor on PreStart and inside the task have it send messages to but it doesn't seem to be working.
I've read some pages about preferring to use PipeTo to wrap a Task but that seems to only be used to retrieve a single result rather than have a separate process continually sending values.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Akka.Actor;
namespace Junk
{
public class Program
{
public static void Main()
{
var system = ActorSystem.Create("my-system");
var actor = system.ActorOf(Props.Create(() => new Manager()));
Console.ReadLine();
}
}
public class Manager : ReceiveActor
{
private Task _task;
public Manager() {
Receive<uint>(msg => { Console.WriteLine($"received {msg}"); });
}
protected override void PreStart() {
Console.WriteLine($"{Self} - PreStart --------------");
startTask();
}
private void startTask() {
_task = Task.Factory.StartNew(() => {
BlockingEnumerable source = new BlockingEnumerable();
Console.WriteLine($"task starting loop -------------");
foreach (uint v in source) {
Self.Tell(v);
}
});
}
}
public class BlockingEnumerable : IEnumerable<uint>
{
public IEnumerator<uint> GetEnumerator() { return new BlockingEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
public class BlockingEnumerator : IEnumerator<uint>
{
private uint value = 0;
public uint Current => value;
object IEnumerator.Current => Current;
public void Dispose() { }
public bool MoveNext() { Thread.Sleep(2000); value += 1; return true; }
public void Reset() { value = 0; }
}
}

Repository cannot be used as a type parameter in the generic type of method

I recently came across a problem which I haven't met before about dependencies and looked it up and found Ninject. I have followed a guide on how to use it and have reached a point where I receive and error which I do not understand. I very generally wrote down the error in the title but the full error is as follows:
'Error 1 The type 'MyDBFirstAP.Repository.SQLAPRepository' cannot be
used as type parameter 'TImplementation' in the generic type or method
'Ninject.Syntax.IBindingToSyntax.To()'. There is
no implicit reference conversion from
'MyDBFirstAP.Repository.SQLAPRepository' to
'MyDBFirstAP.Repository.IAPRepository'.'
It occurs here:
public class NinjectControllerFactory : DefaultControllerFactory{
private IKernel ninjectKernel;
public NinjectControllerFactory() {
ninjectKernel = new StandardKernel();
AddBindings();
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
return controllerType == null
? null
: (IController)ninjectKernel.Get(controllerType);
}
private void AddBindings()
{
ninjectKernel.Bind<IAPRepository>().To<SQLAPRepository>(); // On this line
}
}
The beginning of my controller is as:
public class ClientsController : Controller
{
IAPRepository repository;
// GET: Clients
public ClientsController(IAPRepository repository) {
this.repository = repository;
}
Here is the requested SQLRepository code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MyDBFirstAP.Models;
using MyDBFirstAP.DI;
namespace MyDBFirstAP.Repository {
public class SQLAPRepository {
ApplicationDbContext Database = new ApplicationDbContext();
#region Client
public IQueryable<Client> GetAllClients() {
return Database.Clients;
}
public Client GetClientByID(int id) {
return Database.Clients.FirstOrDefault(c => c.ClientID == id);
}
public IQueryable<Client> GetClientByName(string ClientName) {
return (from clients in Database.Clients
where clients.ClientName.Contains(ClientName)
select clients);
}
public void AddClient(Client client) {
Database.Clients.Add(client);
Database.SaveChanges();
}
public void UpdateClient(Client client) {
var tmpClient = Database.Clients.FirstOrDefault(c => c.ClientID == client.ClientID);
tmpClient.ClientName = client.ClientName;
tmpClient.ClientAddress = client.ClientAddress;
Database.SaveChanges();
}
public void DeleteClient(Client client) {
Database.Clients.Remove(client);
Database.SaveChanges();
}
#endregion
#region Supplier
public IQueryable<Supplier> GetAllSuppliers() {
return Database.Suppliers;
}
public Supplier GetSupplierByID(int id) {
return Database.Suppliers.FirstOrDefault(s => s.SupplierID == id);
}
public IQueryable<Supplier> GetSupplierByName(string SupplierName) {
return(from suppliers in Database.Suppliers
where suppliers.SupplierName.Contains(SupplierName)
select suppliers);
}
public void AddSupplier(Supplier supplier) {
Database.Suppliers.Add(supplier);
Database.SaveChanges();
}
public void UpdateSupplier(Supplier supplier) {
var tmpSupplier = Database.Suppliers.FirstOrDefault(s => s.SupplierID == supplier.SupplierID);
tmpSupplier.SupplierName = supplier.SupplierName;
tmpSupplier.SupplierAddress = supplier.SupplierAddress;
Database.SaveChanges();
}
public void DelteSupplier(Supplier supplier) {
Database.Suppliers.Remove(supplier);
Database.SaveChanges();
}
#endregion
#region Claim
public IQueryable<Claim> GetAllClaims() {
return Database.Claims;
}
public Claim GetClaimByID (int id) {
return Database.Claims.FirstOrDefault(c => c.ClaimID == id);
}
public void AddClaim(Claim claim) {
Database.Claims.Add(claim);
Database.SaveChanges();
}
public void UpdateClaim(Claim claim) {
var tmpClaim = Database.Claims.FirstOrDefault(c => c.ClaimID == claim.ClaimID);
tmpClaim.ClaimTotal = claim.ClaimTotal;
tmpClaim.ClaimWIP = claim.ClaimWIP;
tmpClaim.FK_ClientID = claim.FK_ClientID;
tmpClaim.FK_SupplierID = claim.FK_SupplierID;
Database.SaveChanges();
}
public void DeleteClaim(Claim claim) {
Database.Claims.Remove(claim);
Database.SaveChanges();
}
#endregion
}
}
Can someone please help me understand this error and also help my fix it please. Thank you.
SQLAPRepository must implement IAPRepository.
public class SQLAPRepository : IAPRepository
{
....
}
as Radin said it must implement the IAPRepository interface. When you do dependency injection you're allowing any implementation of an interface to be used at runtime. For production code there is either an explicit configuration mapping or some kind of interrogation of available implementations at runtime.
In NancyFX TinyIoC is used, and it does not require explicit type mapping. For other solutions like Unity there is an explicit type mapping done for many implementations container.RegisterType<IMyInterface,MyImplementation>();

Using FusedLocationApi with Xamarin 3

I had a lot of problems when I tried to use FusedLocationApi from my Xamarin activity. The approach used by the code listed here Location Xamarin has been marked obsolete, so it didn't compile. My implementation is as follows. The question I have is, if this is the way to do it or if I am overlooking something much easier? The LocationHandler is used by my activity, e.g. OnCreate, OnResume, OnPause call the connect and disconnect methods. The OnChangedLocation method should of course do something more intelligent.
using System;
using Android.Gms.Common;
using Android.Gms.Common.Apis;
using Android.Gms.Location;
using Android.Locations;
using Android.Util;
using Android.OS;
using Android.Content;
namespace WithKidsAndroid
{
public class LocationHandler : Java.Lang.Object, IGoogleApiClientConnectionCallbacks, IGoogleApiClientOnConnectionFailedListener, Android.Gms.Location.ILocationListener
{
private IGoogleApiClient _googleAPI;
private Context _context;
public LocationHandler(Context context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
else
{
_context = context;
}
initializeGoogleAPI();
LocRequest = new LocationRequest();
}
public LocationHandler(Context context, LocationRequest request)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
else
{
_context = context;
}
initializeGoogleAPI();
LocRequest = request;
}
public LocationRequest LocRequest
{
get;
set;
}
public void connectGoogleAPI()
{
System.Diagnostics.Debug.Assert(_googleAPI != null);
if (!_googleAPI.IsConnectionCallbacksRegistered(this))
{
_googleAPI.RegisterConnectionCallbacks(this);
}
if (!_googleAPI.IsConnectionFailedListenerRegistered(this))
{
_googleAPI.RegisterConnectionFailedListener(this);
}
if (!_googleAPI.IsConnected || !_googleAPI.IsConnecting)
{
_googleAPI.Connect();
}
}
public void disconnectGoogleAPI()
{
if (_googleAPI != null && _googleAPI.IsConnected)
{
if (_googleAPI.IsConnectionCallbacksRegistered(this))
{
_googleAPI.UnregisterConnectionCallbacks(this);
}
if (_googleAPI.IsConnectionFailedListenerRegistered(this))
{
_googleAPI.UnregisterConnectionFailedListener(this);
}
_googleAPI.Disconnect();
}
}
public void OnConnected(Bundle connectionHint)
{
Log.Debug("LocationHandler", "logged connected", connectionHint);
if (LocRequest == null)
{
throw new Exception("Unknown location request. Set this first by using property LocRequest or constructor.");
}
LocationServices.FusedLocationApi.RequestLocationUpdates(_googleAPI, LocRequest, this);
}
public void OnConnectionSuspended(int cause)
{
Log.Debug("LocationHandler", "logged OnConnectionSuspended", cause);
}
public void OnConnectionFailed(ConnectionResult result)
{
Log.Debug("LocationHandler", "logged OnConnectionFailed", result);
}
public void OnLocationChanged(Location location)
{
Log.Debug("LocationHandler", "logged location changed: " + location.ToString());
}
private void initializeGoogleAPI()
{
int queryResult = GooglePlayServicesUtil.IsGooglePlayServicesAvailable(_context);
if (queryResult == ConnectionResult.Success)
{
_googleAPI = new GoogleApiClientBuilder(_context).AddApi(LocationServices.Api).AddConnectionCallbacks(this).AddOnConnectionFailedListener(this).Build();
}
else
{
var errorString = String.Format("There is a problem with Google Play Services on this device: {0} - {1}", queryResult, GooglePlayServicesUtil.GetErrorString(queryResult));
Log.Error("WithKidsAndroid.LocationHandler", errorString);
throw new Exception(errorString);
}
}
}
}
I guess not. I will close the question, but not remove the question as people can then find an example of LocationServices that work.

The App Get Stuck While Trying To serialize an object in metro app

I'm trying to save the animes dictionary in my app which contains string as key and anime as value but when i use the save function the app just get stuck no exception nothing
here is my Anime.cs Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace AnimeTrackerNew
{
[KnownType(typeof(AnimeTrackerNew.Anime))]
[DataContractAttribute]
class Anime:IComparable<Anime>
{
private string name;
private int season;
private int noe;
private int lw;
private Boolean finished;
public Anime(string name)
: base()
{
this.name = name;
}
public Anime(string name,int season, int noe, int lw)
: base()
{
this.name = name;
this.season = season;
this.noe = noe;
this.lw = lw;
if (lw == noe)
finished=true;
else
finished=false;
}
[DataMember]
public string Name
{
get
{
return name;
}
set
{
this.name = value;
}
}
[DataMember]
public int Season
{
get
{
return season;
}
set
{
this.season = value;
}
}
[DataMember]
public int Noe
{
get
{
return noe;
}
set
{
this.noe = value;
}
}
[DataMember]
public int Lw
{
get
{
return lw;
}
set
{
this.lw = value;
}
}
[DataMember]
public Boolean Finished
{
get
{
return finished;
}
set
{
this.finished = value;
}
}
public int CompareTo(Anime other)
{
return this.Name.CompareTo(other.Name);
}
}
}
and these are the save functions
static async public Task Save()
{
await Windows.System.Threading.ThreadPool.RunAsync((sender) =>
{
Sys.SaveAsync().Wait();
}, Windows.System.Threading.WorkItemPriority.Normal);
}
static async public Task Restore<T>()
{
await Windows.System.Threading.ThreadPool.RunAsync((sender) =>
{
Sys.RestoreAsync<T>().Wait();
}, Windows.System.Threading.WorkItemPriority.Normal);
}
static async private Task SaveAsync<T>()
{
StorageFile sessionFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("animes.xml", CreationCollisionOption.ReplaceExisting);
IRandomAccessStream sessionRandomAccess = await sessionFile.OpenAsync(FileAccessMode.ReadWrite);
IOutputStream sessionOutputStream = sessionRandomAccess.GetOutputStreamAt(0);
DataContractSerializer sessionSerializer = new DataContractSerializer(typeof(Dictionary<string,Anime>), new Type[] { typeof(T) });
sessionSerializer.WriteObject(sessionOutputStream.AsStreamForWrite(), animes);
await sessionOutputStream.FlushAsync();
sessionRandomAccess.Dispose();
}
static async private Task RestoreAsync<T>()
{
StorageFile sessionFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("animes.xml", CreationCollisionOption.OpenIfExists);
if (sessionFile == null)
{
return;
}
IInputStream sessionInputStream = await sessionFile.OpenReadAsync();
DataContractSerializer sessionSerializer = new DataContractSerializer(typeof(Dictionary<string,Anime>), new Type[] { typeof(T) });
animes = (Dictionary<string, Anime>)sessionSerializer.ReadObject(sessionInputStream.AsStreamForRead());
}
}
}
after a little debugging it seems the app get stuck on this line
await sessionOutputStream.FlushAsync();
any help with this one would be appriciated:D
Your exception might get swallowed depending on what thread its thrown on, make sure you're set to break on thrown exceptions in visual studio. You can set this on the debug menu > Exceptions > check Thrown on Common Languange Runtime Exceptions
Also, you could eliminate the Save<T>/Restore<T> method and call SaveAsync<T>/RestoreAsync<T> directly, they are both async anyway so Save<T>/Restore<T> is a little redundant. It also creates a unnecessary call to the threadpool.

Categories