In my datbase I'm using the static late Database _db; to finalize the _db but as i had to use the late initializer here i'm getting this error. Also if i don't use the late initializer i get error where it tells me to use this initializer.
[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: LateInitializationError: Field '_db#26138511' has not been initialized.
import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart'; // for the use of datbase
import 'dart:async';
import 'package:path_provider/path_provider.dart'; // for the use of path
import 'dart:io'; // for the use of new directory
import 'package:path/path.dart'; // to use the join and make a path for our directory
import '../models/user.dart';
class DatabaseHelper {
static final DatabaseHelper _instance = DatabaseHelper.internal();
factory DatabaseHelper() =>
_instance;
// here we'll create some final string for our table that we'll create in the db
final String tableUser = "userTable";
final String columnId = "id";
final String columnUserName = "username";
final String columnPassword = "password";
static late Database _db;
Future<Database> get db async {
if (_db != null) {
return _db;
}
_db =
await initDb();
return _db;
}
DatabaseHelper.internal();
initDb() async {
//get a location using the getDatabasesPath
Directory documentDirectory =
await getApplicationDocumentsDirectory();
String path = join(documentDirectory.path,
"main.db");
//open database
var ourDb = await openDatabase(path, version: 1, onCreate: _onCreate);
return ourDb;
}
// here we'll create the db, and table for our database
/*
id | username | password
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 | Rana | rana
2 | Riya | riya
*/
void _onCreate(Database db, int version) async {
await db.execute(
"CREATE TABLE $tableUser($columnId INTEGER PRIMERY KEY, $columnUserName TEXT, $columnPassword TEXT)"); // this is our dataase id that we created
}
// CREATE, READ, UPDATE, DELETE-----From DATABase
//insertion
Future<int> saveUser(User user) async {
var dbClient = await db;
int result =
await dbClient.insert("$tableUser", user.toMap()); // creating our table
return result;
}
/// get the users
Future<List> getAllUsers() async {
var dbClient = await db;
var result = await dbClient.rawQuery("SELECT * FROM $tableUser");
return result.toList(); // -- making the result to a list
}
/// get counted the id
Future<int?> getCount() async {
var dbClient = await db;
return Sqflite.firstIntValue(
await dbClient.rawQuery("SELECT COUNT(*) FROM $tableUser"),
);
}
/// get only one user from database
Future<User?> getUser(int id) async {
var dbClient = await db;
var result = await dbClient
.rawQuery("SELECT * FROM $tableUser WHERE $columnId = $id");
if (result.length == 0) return null;
return User.fromMap(result.first);
}
/// delete from the database
Future<int> deletUser(int id) async {
var dbClient = await db;
return await dbClient
.delete(tableUser, where: "$columnId = ?", whereArgs: [id]);
}
/// update the database
Future<int> updateUser(User user) async {
var dbClient = await db;
return await dbClient.update(tableUser, user.toMap(),
where: "$columnId = ?", whereArgs: [user.id]);
}
/// closeing the database
Future closeDatabase() async {
var dbClient = await db;
return dbClient.close();
}
}
Dart null-safety feature does not promote class fields when doing. refer to here
if (_db == null)
the solution would be to rewrite:
static late Database _db;
Future<Database> get db async {
if (_db != null) {
return _db;
}
_db = await initDb();
return _db;
}
to:
static Database? _database;
Future<Database> get db async => _db ??= await _initiateDatabase();
The ??= operator will check if _db is null and set it to the value of await _initiateDatabase()
if that is the case and then return the new value of _db, or return if it already has a value
and finally enforce the datatype on db initialisation, to avoid future problems
...
Future<Database> initDb() async {
...
Related
Flutter database objectbox error - " Unsupported operation: Cannot create multiple Store instances for the same directory in the same isolate. Please use a single Store, close() the previous instance before opening another one or attach to it in another isolate ". I am using objectbox as my app database.How can I solve this problem. Here is my code -
// First File
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../objectbox.g.dart';
#Entity()
class MarkEvent {
int? id;
int habitId;
String dateTime;
MarkEvent({required this.dateTime, required this.habitId, this.id = 0});
}
class HabitDetailProvider with ChangeNotifier {
List<MarkEvent> marks = [];
Future<void> deleteMark(int id) async {
final index = marks.indexWhere((element) => element.id == id);
marks.removeAt(index);
var store = await openStore();
var box = store.box<MarkEvent>();
box.remove(id);
store.close();
// await DataBaseHelper.deleteEvent(id);
notifyListeners();
}
Future<void> addMark(MarkEvent mark) async {
marks.add(MarkEvent(dateTime: mark.dateTime, habitId: mark.habitId));
var store = await openStore();
var box = store.box<MarkEvent>();
box.put(mark);
store.close();
notifyListeners();
}
Future<void> fetchAndSetMarks() async {
var store = await openStore();
var box = store.box<MarkEvent>();
final markList = box.query().build().find();
store.close();
marks = markList
.map((e) => MarkEvent(dateTime: e.dateTime, habitId: e.habitId))
.toList();
notifyListeners();
}
}
// Another file
import 'package:flutter/material.dart';
import 'package:habit_app/objectbox.g.dart';
import '../model/habit_model.dart';
class HabitListNotifier with ChangeNotifier {
List<HabitModel> _habitList = [];
List<HabitModel> get Habit_List {
return [..._habitList];
}
Future<Store> get originalStore {
return openStore();
}
void addHabit(HabitModel habit) async {
HabitModel newHabit = HabitModel(
hour: habit.hour,
minutes: habit.minutes,
reminderHour: habit.reminderHour,
reminderMinute: habit.reminderMinute,
alarmId: habit.alarmId,
notificationText: habit.notificationText,
reason: habit.reason,
notificationId: habit.notificationId,
iconData: habit.iconData.toString(),
title: habit.title,
plan: habit.plan,
);
_habitList.add(newHabit);
var store = await originalStore;
var box = store.box<HabitModel>();
box.put(habit);
store.close();
notifyListeners();
}
void updateHabit(HabitModel newHabit) async {
final oldHabitIndex =
_habitList.indexWhere((habit) => habit.id == newHabit.id);
_habitList[oldHabitIndex] = newHabit;
var store = await originalStore;
var box = store.box<HabitModel>();
box.put(newHabit);
store.close();
notifyListeners();
}
Future<void> fetchAndSetHabits() async {
var store = await originalStore;
var box = store.box<HabitModel>();
var query = box.query().build();
_habitList = query.find();
store.close();
notifyListeners();
}
Future<void> deleteHabit(int id) async {
final existingHabit = _habitList.indexWhere((element) => element.id == id);
_habitList.removeAt(existingHabit);
var store = await originalStore;
var box = store.box<HabitModel>();
box.remove(id);
store.close();
notifyListeners();
}
}
// Another file
import 'package:flutter/material.dart';
import 'package:habit_app/providers/habit_provider.dart';
import 'package:provider/provider.dart';
import '../objectbox.g.dart';
class NoteModel {
int habitId;
int? id;
String dateTime;
String note;
NoteModel(
{required this.dateTime,
required this.habitId,
this.id = 0,
required this.note});
}
class Notes with ChangeNotifier {
List<NoteModel> notes = [];
List<NoteModel> get dupNoteList {
return notes;
}
Future<void> addNote(
NoteModel note, int habitId, BuildContext context) async {
notes.add(note);
var store = await Provider.of<HabitListNotifier>(context, listen: false)
.originalStore;
var box = store.box<NoteModel>();
box.put(note);
store.close();
fetchAndSetNotes(habitId);
notifyListeners();
}
Future<void> deleteNote(int id) async {
final index = notes.indexWhere((element) => element.id == id);
notes.removeAt(index);
var store = await openStore();
var box = store.box<NoteModel>();
box.remove(id);
store.close();
notifyListeners();
}
Future<void> updateNote(NoteModel newNote) async {
var store = await openStore();
var box = store.box<NoteModel>();
box.put(newNote);
store.close();
final oldNote = notes.indexWhere((habit) => habit.id == newNote.id);
notes[oldNote] = newNote;
notifyListeners();
}
Future<void> fetchAndSetNotes(int habitId) async {
var store = await openStore();
var box = store.box<NoteModel>();
var query = box.query().build();
final note = query.find();
store.close();
notes = note.where((notes) => notes.habitId == habitId).toList();
notifyListeners();
}
}
//Models file
import 'package:objectbox/objectbox.dart';
#Entity()
class NoteModel {
String habitId;
int? id;
String dateTime;
String note;
NoteModel({
required this.dateTime,
required this.habitId,
required this.note,
this.id = 0,
});
}
import 'dart:core';
import 'package:objectbox/objectbox.dart';
class ClockTime {
int? id;
int hour;
int minutes;
ClockTime(this.hour, this.minutes);
}
#Entity()
class HabitModel {
String title;
String reason;
String plan;
String iconData;
int? id;
int alarmId;
int notificationId;
String notificationText;
int hour;
int reminderHour;
int reminderMinute;
int minutes;
HabitModel({
required this.reason,
required this.notificationText,
required this.reminderHour,
required this.reminderMinute,
required this.notificationId,
required this.plan,
required this.alarmId,
required this.iconData,
required this.title,
this.id = 0,
required this.hour,
required this.minutes,
});
}
I’m developing a small Windows form app to test Graph API functions. I have two functionalities in the application, user's log in and get channels for specified team. I created a class that contains functions for user login and for returning channels for specified team. I have a ListView on Form in which I want to show all the channels, but when I call a function for returning channels in button event, nothing happens, nothing is displayed in the ListView. Here is the code:
public static class GraphHelper
{
public static GraphServiceClient graphClient;
public static string token;
private static string[] scopes = new string[] { "user.read" };
public static string TokenForUser = null;
public static DateTimeOffset expiration;
private const string ClientId = "599ed98d-4356-4a96-ad37-04391e9c48dc";
private const string Tenant = "common"; // Alternatively "[Enter your tenant, as obtained from the Azure portal, e.g. kko365.onmicrosoft.com]"
private const string Authority = "https://login.microsoftonline.com/" + Tenant;
// The MSAL Public client app
private static IPublicClientApplication PublicClientApp;
private static string MSGraphURL = "https://graph.microsoft.com/beta/";
private static AuthenticationResult authResult;
public static GraphServiceClient GetGraphClient(string token)
{
if (graphClient == null)
{
// Create Microsoft Graph client.
try
{
graphClient = new GraphServiceClient(
"https://graph.microsoft.com/v1.0",
new DelegateAuthenticationProvider(
async (requestMessage) =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
// This header has been added to identify our sample in the Microsoft Graph service. If extracting this code for your project please remove.
requestMessage.Headers.Add("SampleID", "uwp-csharp-snippets-sample");
}));
return graphClient;
}
catch (Exception ex)
{
Debug.WriteLine("Could not create a graph client: " + ex.Message);
}
}
return graphClient;
}
public static async Task<string> GetTokenForUserAsync()
{
if (TokenForUser == null || expiration <= DateTimeOffset.UtcNow.AddMinutes(10))
{
PublicClientApp = PublicClientApplicationBuilder.Create(ClientId)
.WithAuthority(Authority)
.WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient")
.WithLogging((level, message, containsPii) =>
{
Debug.WriteLine($"MSAL: {level} {message} ");
}, LogLevel.Warning, enablePiiLogging: false, enableDefaultPlatformLogging: true)
.Build();
// It's good practice to not do work on the UI thread, so use ConfigureAwait(false) whenever possible.
IEnumerable<IAccount> accounts = await PublicClientApp.GetAccountsAsync().ConfigureAwait(false);
IAccount firstAccount = accounts.FirstOrDefault();
try
{
authResult = await PublicClientApp.AcquireTokenSilent(scopes, firstAccount)
.ExecuteAsync();
}
catch (MsalUiRequiredException ex)
{
// A MsalUiRequiredException happened on AcquireTokenSilentAsync. This indicates you need to call AcquireTokenAsync to acquire a token
Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");
authResult = await PublicClientApp.AcquireTokenInteractive(scopes)
.ExecuteAsync()
.ConfigureAwait(false);
}
TokenForUser = authResult.AccessToken;
}
return TokenForUser;
}
public static async Task<User> GetMeAsync(string token)
{
GraphHelper.graphClient = GraphHelper.GetGraphClient(token);
try
{
// GET /me
return await GraphHelper.graphClient.Me
.Request()
.Select(u => new
{
u.DisplayName
})
.GetAsync();
}
catch (ServiceException ex)
{
Console.WriteLine($"Error getting signed-in user: {ex.Message}");
return null;
}
}
public static async Task<IEnumerable<Channel>> GetChannels(string teamId)
{
graphClient = GetGraphClient(token);
var channels = await graphClient.Teams[teamId].Channels
.Request()
.GetAsync();
return channels;
}
}
public partial class Form1 : Form
{
public static GraphServiceClient graphClient;
public static string token;
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
token = await GraphHelper.GetTokenForUserAsync();
User graphUser = await GraphHelper.GetMeAsync(token);
label2.Text = graphUser.DisplayName;
}
private async void button3_Click(object sender, EventArgs e)
{
var channels = GraphHelper.GetChannels("8557483b-a233-4710-82de-e1bdb03bb9a9").Result;
foreach (var ch in channels)
{
ListViewItem item = new ListViewItem(new string[] { ch.DisplayName, ch.Id});
listView1.Items.Add(item);
}
}
}
Does anyone how to solve this?
Try to call GraphHelper.GetChannels with await keyword on button click.
var channels = await GraphHelper.GetChannels("8557483b-a233-4710-82de-e1bdb03bb9a9");
This is a todo list app and uses a database to use the CRUD functions. When the user does a specific action such as tap or swipe i want to mark the task as complete. I am a bit new to databases and am unsure on how to use update item to update the status of a task (completed or not completed).
Could i get a suggestion on what is the correct way to update the _isDone value without deleting a task from the database
Tried to search for other examples of to do list apps but they delete the completed task intead of marking it as completed
database code -
//This is the database
String _itemName;
String _dateCreated;
int _id;
bool _isDone;
TodoItem(this._itemName, this._dateCreated, [this._isDone]);
TodoItem.map(dynamic obj) {
this._itemName = obj["itemName"];
this._dateCreated = obj["dateCreated"];
this._id = obj["id"];
this._isDone = obj["isDone"];
}
String get itemName => _itemName;
String get dateCreated => _dateCreated;
int get id => _id;
bool get isDone => _isDone;
Map<String, dynamic> toMap() {
var map = new Map<String, dynamic>();
map["itemName"] = _itemName;
map["dateCreated"] = _dateCreated;
if (_id != null) {
map["id"] = _id;
}
return map;
}
TodoItem.fromMap(Map<String, dynamic> map) {
this._itemName = map["itemName"];
this._dateCreated = map["dateCreated"];
this._id = map["id"];
this._isDone = map["isDone"];
}
update item function -
Future<int> updateItem(TodoItem item) async {
var dbClient = await db;
return await dbClient.update("$tableName", item.toMap(),
where: "$columnId = ?", whereArgs: [item.id]);
}
please reference this document https://medium.com/flutter-community/using-sqlite-in-flutter-187c1a82e8b
In sqlite example below, update the whole record via a key, "id" here
updateClient(Client newClient) async {
final db = await database;
var res = await db.update("Client", newClient.toMap(),
where: "id = ?", whereArgs: [newClient.id]);
return res;
}
In your example, you update TodoItem and TodoItem include isDone field.
and your syntax is correct
another reference doc https://www.developerlibs.com/2018/07/flutter-sqlite-database-example.html
code snippet of this example
Future<bool> update(User user) async {
var dbClient = await db;
int res = await dbClient.update("User", user.toMap(),
where: "id = ?", whereArgs: <int>[user.id]);
return res > 0 ? true : false;
}
official document about use of sqlite https://flutter.dev/docs/cookbook/persistence/sqlite
code snippet of official document
Future<void> updateDog(Dog dog) async {
// Get a reference to the database.
final db = await database;
// Update the given Dog.
await db.update(
'dogs',
dog.toMap(),
// Ensure that the Dog has a matching id.
where: "id = ?",
// Pass the Dog's id as a whereArg to prevent SQL injection.
whereArgs: [dog.id],
);
}
// Update Fido's age.
await updateDog(Dog(
id: 0,
name: 'Fido',
age: 42,
));
You can build a Database Helper as the example and include your update function
import 'dart:async';
import 'dart:io' as io;
import 'package:flutter_database/database/model/user.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
class DatabaseHelper {
static final DatabaseHelper _instance = new DatabaseHelper.internal();
factory DatabaseHelper() => _instance;
static Database _db;
Future<Database> get db async {
if (_db != null) return _db;
_db = await initDb();
return _db;
}
DatabaseHelper.internal();
initDb() async {
io.Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "main.db");
var theDb = await openDatabase(path, version: 1, onCreate: _onCreate);
return theDb;
}
void _onCreate(Database db, int version) async {
// When creating the db, create the table
await db.execute(
"CREATE TABLE User(id INTEGER PRIMARY KEY, firstname TEXT, lastname TEXT, dob TEXT)");
}
Future<int> saveUser(User user) async {
var dbClient = await db;
int res = await dbClient.insert("User", user.toMap());
return res;
}
Future<List<User>> getUser() async {
var dbClient = await db;
List<Map> list = await dbClient.rawQuery('SELECT * FROM User');
List<User> employees = new List();
for (int i = 0; i < list.length; i++) {
var user =
new User(list[i]["firstname"], list[i]["lastname"], list[i]["dob"]);
user.setUserId(list[i]["id"]);
employees.add(user);
}
print(employees.length);
return employees;
}
Future<int> deleteUsers(User user) async {
var dbClient = await db;
int res =
await dbClient.rawDelete('DELETE FROM User WHERE id = ?', [user.id]);
return res;
}
Future<bool> update(User user) async {
var dbClient = await db;
int res = await dbClient.update("User", user.toMap(),
where: "id = ?", whereArgs: <int>[user.id]);
return res > 0 ? true : false;
}
}
I have a multitenant app secure with an IdentityServer4 implementation. I recently updated it to the latest ID4 and the behavior seems to have changed. Previously, I could make a request with the TokenClient inside of the IdentityModel package:
var parameters = new Dictionary<string, string>();
parameters.Add("username", loginModel.UserName);
parameters.Add("password", loginModel.Password);
var tokenClient = new TokenClient(new Uri(new Uri(accountsConfig.EndpointUrl), "/connect/token").ToString(), accountsConfig.ClientId, accountsConfig.Secret, null, AuthenticationStyle.PostValues);
var tokenResponse = await tokenClient.RequestCustomGrantAsync("AgentLogin", extra: parameters);
It would return all of the scopes defined for the client in the token. That is no longer the case. How do I configure ID4 to do that without explicitly requesting them inside of the TokenClient?
public class AgentLoginCustomGrantValidator : IExtensionGrantValidator
{
private readonly ILogger<AgentLoginCustomGrantValidator> _logger;
private readonly IAdminUserService _adminUserService;
public AgentLoginCustomGrantValidator(ILogger<AgentLoginCustomGrantValidator> logger, IAdminUserService adminUserService)
{
_logger = logger;
_adminUserService = adminUserService;
}
public async Task ValidateAsync(ExtensionGrantValidationContext context)
{
try
{
var username = context.Request.Raw.Get("username");
var password = context.Request.Raw.Get("password");
var userId = _adminUserService.AuthenticateUser(username, password);
if (userId != null)
{
var agencyUser = _adminUserService.GetUser(userId.Value);
context.Result = new GrantValidationResult($"{userId}", GrantType, agencyUser.Roles.Select(x => new Claim(JwtClaimTypes.Role, x.Name)).Concat(new List<Claim>() { new Claim(JwtClaimTypes.Name, agencyUser.UserName) { } }));
}
else
{
_logger.LogWarning($"Bum creds: {username} ");
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidClient, "Invalid credentials");
}
}
catch (Exception ex)
{
_logger.LogError(ex.ToString());
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidClient, ex.Message);
}
}
public string GrantType => "AgentLogin";
}
Looks like Identity Server 4 by default only returns the requested identity or api resources for each client. However, this behaviour can be easily overridden to return all the scopes regardless whether they were requested in the token request or not. You can create a CustomClaimsService which inherits from the DefaultClaimsService.
public class CustomClaimsService : DefaultClaimsService
{
public CustomClaimsService(IProfileService profile, ILogger<DefaultClaimsService> logger) : base(profile, logger)
{
}
public override async Task<IEnumerable<Claim>> GetAccessTokenClaimsAsync(ClaimsPrincipal subject,
Resources resources, ValidatedRequest request)
{
var baseResult = await base.GetAccessTokenClaimsAsync(subject, resources, request);
var outputClaims = baseResult.ToList();
//If there are any allowed scope claims that are not yet in the output claims - add them
foreach (var allowedClientScope in request.Client.AllowedScopes)
{
if (!outputClaims.Any(x => x.Type == JwtClaimTypes.Scope && x.Value == allowedClientScope))
{
outputClaims.Add(new Claim(JwtClaimTypes.Scope, allowedClientScope));
}
}
return outputClaims;
}
}
Then just register it with the IdentityServerBuilder service container.
var builder = services.AddIdentityServer(options =>
{
//Your identity server options
});
//Register the custom claims service with the service container
builder.Services.AddTransient<IClaimsService, CustomClaimsService>();
Each access token will now contain all the scopes that the given client is allowed.
I'm trying to find the best solution to have a local database in my WP8.1 application.
I'm using the standard WP8.1 (non-SL) and Visual Studio 2013.
I've looked into SQLite but I couldn't manage to get it to work on my application/Visual Studio.
If I can use SQLite, I need someone to point me out the way to go. Else, please refer me the best solution.
Thanks in advance!
Here's a repository class that leverages SQLite:
public class ContactsRepository : IContactsRepository
{
SQLiteAsyncConnection _connection = null;
static ContactsRepository _repository = null;
private ContactsRepository()
{
}
public async Task Initialize()
{
_connection = new SQLiteAsyncConnection(Constants.DATABASE_FILE_NAME);
await EnsureTableExist<ContactReference>(_connection);
}
public static ContactsRepository Instance
{
get
{
if (_repository == null)
{
_repository = new ContactsRepository();
}
return _repository;
}
}
public async Task Add(Category category, Contact contact)
{
var result = await _connection.Table<ContactReference>().Where(c => c.ContactId == contact.Id).FirstOrDefaultAsync();
if (result != null)
{
result.CategoryName = category.Name;
await _connection.UpdateAsync(result);
}
else
{
await _connection.InsertAsync(new ContactReference()
{
CategoryName = category.Name,
ContactId = contact.Id
});
}
}
public async Task Update(Category category, Contact contact)
{
var result = await _connection.Table<ContactReference>().Where(c => c.ContactId == contact.Id).FirstOrDefaultAsync();
Debug.Assert(result != null);
if (result == null)
{
throw new Exception("Unable to update category. Candidate not found");
}
if (result != null)
{
result.CategoryName = category.Name;
await _connection.UpdateAsync(result);
}
}
public async Task<ObservableCollection<Contact>> Get(string categoryName)
{
var result = new ObservableCollection<Contact>();
var query = _connection.Table<ContactReference>().Where(c => c.CategoryName == categoryName);
var queryResult = await query.ToListAsync();
foreach(var contact in queryResult)
{
var phoneContacts = ResourceLocator.Instance[typeof(ObservableCollection<Contact>)] as ObservableCollection<Contact>;
var phoneContact = phoneContacts.Where(c => c.Id == contact.ContactId).FirstOrDefault();
Debug.Assert(phoneContact != null);
if (phoneContact != null)
{
result.Add(phoneContact);
}
}
return result;
}
public async Task<ObservableCollection<ContactReference>> Get()
{
var result = new ObservableCollection<ContactReference>();
var query = _connection.Table<ContactReference>();
var queryResult = await query.ToListAsync();
foreach (var contact in queryResult)
{
result.Add(contact);
}
return result;
}
private async Task EnsureTableExist<T>(SQLiteAsyncConnection connection) where T : new()
{
bool noTableExists = false;
try
{
var query = await connection.Table<T>().FirstOrDefaultAsync();
}
catch (SQLiteException ex)
{
if (ex.Message.Contains("no such table"))
{
noTableExists = true;
}
}
if (noTableExists)
{
await connection.CreateTableAsync<T>();
}
}
}