Я не уверен, почему вы упоминаете набор инструментов, насколько мне известно, вы получаете доступ к функциям SQLite программно.
Пакеты NuGet, которые я недавно использовал для проекта Xamarin (SQLite- net - pcl от Фрэнка Крюгера и вспомогательные библиотеки) позволили мне использовать довольно простое сопоставление объектов без обращения к SQL строкам.
Я использую много интерфейсов в своем коде, но вот мой класс базы данных с полным доступом
:
public class AllAccessDataTableBaseSqLite<T> : IDataAccessRead<T>, IDataAccessWrite<T>,IDataAccessExpressionSearch<T>, IDataAccessDelete<T> where T: IDataRecord, new()
{
//Note that this static value will only apply to those classes based on the same generic type e.g. all DataTableBase<User> instances etc.
public static SQLiteAsyncConnection DBConnection;
/// <summary>
/// Lock object to prevent multi-thread interruption of code segment.
/// </summary>
public static readonly object CollisionLock = new object();
/// <summary>
/// Constructor
/// </summary>
public AllAccessDataTableBaseSqLite()
{
lock (CollisionLock)
{
if (DBConnection != null)
{
DBConnection.CreateTableAsync<T>().Wait();
return;
}
try
{
string directory;
if (DeviceInfo.Platform != DevicePlatform.Unknown)
{
directory = FileSystem.AppDataDirectory;
}
else
{
directory = "DataStore";
var directoryInfo = Directory.CreateDirectory(directory);
directory = directoryInfo.FullName;
}
var path = Path.Combine(directory, $"{typeof(T).Name}.db");
if (!File.Exists(path))
{
using var fileStream = File.Create(path);
fileStream.Close();
}
DBConnection = new SQLiteAsyncConnection(path);
DBConnection.CreateTableAsync<T>().Wait();
}
catch (Exception ex)
{
if (ex is UnauthorizedAccessException)
{
}
}
}
}
/// <summary>
/// Create the data table
/// </summary>
/// <returns></returns>
public async Task<CreateTableResult> CreateTableAsync()
{
if (DBConnection != null)
{
return await DBConnection.CreateTableAsync<T>();
}
return CreateTableResult.Migrated;
}
/// <summary>
/// Create a new record entry
/// </summary>
/// <param name="entity">Data entity to enter</param>
/// <param name="user">Current User information</param>
/// <returns>New entry record if successful</returns>
public async Task<T> CreateAsync(T entity, IUserRecord user)
{
if (entity == null)
{
return default(T);
}
if (DBConnection == null)
{
return default(T);
}
entity.CreatedDate = DateTime.UtcNow;
entity.CreatedByUserId = user.Id;
entity.Id = 0;
try
{
await DBConnection.InsertAsync(entity);
}
catch (SQLiteException e)
{
if (e.Message == "Constraint")
{
throw new InvalidConstraintException(e.Message, e.InnerException);
}
}
var result = entity;
return result;
}
/// <summary>
/// Update a collection of new entities of type T to the data table.
/// All entities should be present within the data table
/// </summary>
/// <param name="entityList">Entity collection</param>
/// <param name="user">user making the change</param>
/// <returns>ID of entities successfully updated or added</returns>
public async Task<int> UpdateAllAsync(IEnumerable<T> entityList, IUserRecord user)
{
var result = 0;
foreach (var t in entityList)
{
if (null != await UpdateAsync(t, user))
{
result++ ;
}
}
return result;
}
/// <summary>
/// Obtain the data record with the given Id
/// </summary>
/// <param name="id">Id value to select the record by</param>
/// <returns>A valid record if found otherwise null</returns>
public async Task<T> GetById(int id)
{
if (DBConnection == null)
{
return default(T);
}
return await DBConnection.Table<T>().Where(i => i.Id == id).FirstOrDefaultAsync();
}
/// <summary>
/// This function returns all database entries that are not marked deleted or changed
/// Warning: The data set may be very large
/// </summary>
/// <returns>A list of entries</returns>
public async Task<List<T>> GetAll()
{
if (DBConnection != null)
{
return await DBConnection.Table<T>().Where(x=>x.ChangedDate==default && x.DeletedDate==default)
.ToListAsync();
}
return new List<T>();
}
/// <inheritdoc />
public async Task<List<T>> GetAllHistoric() => await DBConnection.Table<T>().ToListAsync();
/// <summary>
/// This function is used to update the supplied record entry within the database.
/// If the supplied record does not have a non-zero value Id field it is assumed to be a
/// new record to be inserted into the database.
/// </summary>
/// <param name="entity">Record to update</param>
/// <param name="user">User performing the action</param>
/// <returns></returns>
public async Task<T> UpdateAsync(T entity, IUserRecord user)
{
if (DBConnection == null)
{
return default(T);
}
if (entity == null)
{
return default(T);
}
var newRecord = (T) ((entity) as BaseRecord<T>)?.Clone();
if (null == newRecord)
{
return default(T);
}
//if Id is zero assume that the record is new and to be added
if (newRecord.Id == 0)
{
if (user != null)
{
newRecord.CreatedByUserId = user.Id;
}
newRecord.CreatedDate = DateTime.UtcNow;
newRecord.Id = await DBConnection.InsertAsync(newRecord);
return newRecord;
}
// Id is not zero and thus a new record should be created linked to the old record.
var oldRecord = await GetById(newRecord.Id);
oldRecord.ChangedDate = DateTime.UtcNow;
if (user != null)
{
oldRecord.ChangedByUserId = user.Id;
}
try
{
var result = await DBConnection.UpdateAsync(oldRecord);
}
catch (Exception e)
{
Debug.WriteLine($"UpdateAsync {e.Message}");
}
newRecord.PreviousRecordId = oldRecord.Id;
newRecord.Id = 0;
return await CreateAsync(newRecord, user);
}
/// <inheritdoc />
public async Task<int> DeleteAsync(T entity)
{
if (DBConnection == null)
{
return -1;
}
return await DBConnection.DeleteAsync(entity);
}
/// <inheritdoc />
public async Task DeleteAll()
{
await DBConnection.DropTableAsync<T>();
await CreateTableAsync();
}
/// <inheritdoc />
public async Task<PagedResult<T>> GetAllPagedResult(int recordId, uint maxResults = 100)
{
if (DBConnection == null)
{
return null;
}
List<T> list;
if (maxResults == 0)
{
list = await GetAll();
}
else
{
list = await DBConnection.Table<T>().Where(x => (x.Id >= recordId && x.ChangedDate == default && x.DeletedDate == default)).ToListAsync();
if (list.Count() > maxResults)
{
list = list.GetRange(0, (int) maxResults);
}
}
return new PagedResult<T>(list, list.Count());
}
/// <inheritdoc />
public async Task<IEnumerable<T>> FindAsyncOrdered<TValue>(Expression<Func<T, bool>> predicate = null,
Expression<Func<T, TValue>> orderBy = null)
{
var query = DBConnection.Table<T>();
if (predicate != null)
{
query = query.Where(predicate);
}
if (orderBy != null)
{
query = query.OrderBy<TValue>(orderBy);
}
return await query.ToListAsync();
}
/// <inheritdoc />
public async Task<T> FindFirst(Expression<Func<T, bool>> predicate) => await DBConnection.FindAsync(predicate);
}
Я использую классы данных на основе:
public interface IDataRecord
{
/// <summary>
/// Identifier for record
/// </summary>
int Id { get; set; }
/// <summary>
/// Link to previous version of record
/// </summary>
int PreviousRecordId { get; set; }
/// <summary>
/// User Identity that made the change
/// </summary>
int ChangedByUserId { get; set; }
/// <summary>
/// Date when the data record was last changed
/// </summary>
DateTime ChangedDate { get; set; }
/// <summary>
/// Identity of User that deleted the record
/// </summary>
int DeletedByUserId { get; set; }
/// <summary>
/// Date when the data record was deleted
/// </summary>
DateTime DeletedDate { get; set; }
/// <summary>
/// Identity of User that created the record
/// </summary>
int CreatedByUserId { get; set; }
/// <summary>
/// Date when the data record was added
/// </summary>
DateTime CreatedDate { get; set; }
object Clone();
}
Очевидно, вам не обязательно использовать это, но, проще говоря, для моей реализации приложения каждый тип записи данных хранится в собственный файл данных (то есть по одной таблице на файл), и он создается в начале в конструкторе.
edit
Я внимательно изучил ваш код. На заметку:
Похоже, вы не создаете таблицу.
Доступ к папкам, не относящимся к приложениям, ограничен, если вы решил создать UWP, а не базовый проект WPF - помните о разрешениях доступа к папкам при запуске приложений, особенно в режиме выпуска.