Xamarin 项目中 SQLite-Net 的通用存储库
Posted
技术标签:
【中文标题】Xamarin 项目中 SQLite-Net 的通用存储库【英文标题】:Generic Repository for SQLite-Net in Xamarin Project 【发布时间】:2015-05-17 00:10:48 【问题描述】:我想知道是否有一种方法可以为我的 Xamarin 项目编写通用存储库,而不是为我的对象中的每个实体编写不同的存储库。 Xamarin Tasky Pro 示例有一个用于任务实体的存储库,因为这是它拥有的唯一实体。
在我自己的项目中,我有多个实体,所以我的问题是如何制作 以下 Customer Repository 成为通用的,以便 ProductManager、EmployeeManager 等可以使用它。如果您知道示例或博客文章,请指出正确的方向
namespace App.DataLayer
public class CustomerRepository
private ProntoDatabase _db = null;
protected static string DbLocation;
protected static CustomerRepository Me;
static CustomerRepository()
Me = new CustomerRepository();
protected CustomerRepository()
//set the db location;
DbLocation = DatabaseFilePath;
//instantiate the database
_db = new ProntoDatabase(DbLocation);
public static string DatabaseFilePath
get
const string sqliteFilename = "CustomerDB.db3";
var libraryPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
var path = Path.Combine(libraryPath, sqliteFilename);
return path;
// CRUD (Create, Read, Update and Delete) methods
public static Customer GetCustomer(int id)
return Me._db.GetItem<Customer>(id);
public static IEnumerable<Customer> GetCustomers()
return Me._db.GetItems<Customer>();
public static int SaveCustomer(Customer item)
return Me._db.SaveItem(item);
public static int DeleteCustomer(int id)
return Me._db.DeleteItem<Customer>(id);
【问题讨论】:
您现在必须在 SQLiteConnectionWithLock 和 SQLiteConnection 构造函数中传入 ISQlitePlatform 的实现。正确的平台实现会自动添加到项目中。 【参考方案1】:这是一个老问题,但这是我的实现。
我正在使用异步连接,因为它们在移动项目中提供了更好的性能。我安装的nuggets在Core项目上是Sqlite.Net-PCL
/SQLite.Net.Async-PCL
,在android项目上是对应的nuget。
我的存储库如下所示:
using System;
using System.Collections.Generic;
using Core.Models;
using SQLite.Net;
using System.Linq;
using SQLite.Net.Async;
using System.Threading.Tasks;
using System.Linq.Expressions;
namespace Core.Managers
public interface IRepository<T> where T : class, new()
Task<List<T>> Get();
Task<T> Get(int id);
Task<List<T>> Get<TValue>(Expression<Func<T, bool>> predicate = null, Expression<Func<T, TValue>> orderBy = null);
Task<T> Get(Expression<Func<T, bool>> predicate);
AsyncTableQuery<T> AsQueryable();
Task<int> Insert(T entity);
Task<int> Update(T entity);
Task<int> Delete(T entity);
public class Repository<T> : IRepository<T> where T : class, new()
private SQLiteAsyncConnection db;
public Repository(SQLiteAsyncConnection db)
this.db = db;
public AsyncTableQuery<T> AsQueryable() =>
db.Table<T>();
public async Task<List<T>> Get() =>
await db.Table<T>().ToListAsync();
public async Task<List<T>> Get<TValue>(Expression<Func<T, bool>> predicate = null, Expression<Func<T, TValue>> orderBy = null)
var query = db.Table<T>();
if (predicate != null)
query = query.Where(predicate);
if (orderBy != null)
query = query.OrderBy<TValue>(orderBy);
return await query.ToListAsync();
public async Task<T> Get(int id) =>
await db.FindAsync<T>(id);
public async Task<T> Get(Expression<Func<T, bool>> predicate) =>
await db.FindAsync<T>(predicate);
public async Task<int> Insert(T entity) =>
await db.InsertAsync(entity);
public async Task<int> Update(T entity) =>
await db.UpdateAsync(entity);
public async Task<int> Delete(T entity) =>
await db.DeleteAsync(entity);
一些使用方法的例子:
var connection = new SQLiteAsyncConnection(() => sqlite.GetConnectionWithLock());
await connection.CreateTablesAsync<Ingredient, Stock>();
IRepository<Stock> stockRepo = new Repository<Stock>(connection);
IRepository<Ingredient> ingredientRepo = new Repository<Ingredient>(connection);
var stock1 = new Stock
IngredientId = 1,
DaysToExpire = 3,
EntryDate = DateTime.Now,
Location = StockLocations.Fridge,
MeasureUnit = MeasureUnits.Liter,
Price = 5.50m,
ProductName = "Leche Auchan",
Quantity = 3,
Picture = "test.jpg",
Family = IngredientFamilies.Dairy
;
var stockId = await stockRepo.Insert(stock1);
var all = await stockRepo.Get();
var single = await stockRepo.Get(72);
var search = await stockRepo.Get(x => x.ProductName.StartsWith("something"));
var orderedSearch = await stockRepo.Get(predicate: x => x.DaysToExpire < 4, orderBy: x => x.EntryDate);
如果 Repository 不能满足你的查询需求,你可以使用 AsQueryable():
public async Task<List<Stock>> Search(string searchQuery, StockLocations location, IngredientFamilies family)
var query = stockRepo.AsQueryable();
if (!string.IsNullOrEmpty(searchQuery))
query = query.Where(x => x.ProductName.Contains(searchQuery) || x.Barcode.StartsWith(searchQuery));
if (location != StockLocations.All)
query = query.Where(x => x.Location == location);
if (family != IngredientFamilies.All)
query = query.Where(x => x.Family == family);
return await query.OrderBy(x => x.ExpirationDays).ToListAsync();
【讨论】:
哇,太好了。这正是我正在寻找的。我会使用它,看看我是否可以用它来替换我的 7 个不同的存储库 所有者有未列出的Sqlite.Net.Platform.XamarinAndroid
包。这可能意味着该软件包已被弃用或不应再使用。 LINK
没有“public class Repository我在 unity IOC 的帮助下实现如下,我的项目包括 PCL、Xamarin Android 和 Xamarin ios 项目
使用主键定义基本模型
public class BaseModel
[PrimaryKey, AutoIncrement]
public int Id get; set;
定义一个通用的基础存储库,如下所示
public interface IBaseRepository<T> : IDisposable
where T :BaseModel, new()
List<T> GetItems();
T GetItem(int id);
int GetItemsCount();
int SaveItem(T item);
int SaveAllItem(IEnumerable<T> items);
public class BaseRepository<T> : BaseRepository<T> where T : BaseModel, new()
private static readonly object locker = new object();
protected SQLiteConnection DatabaseConnection;
public BaseRepository(string dbPath)
DatabaseConnection = new SQLiteConnection(dbPath);
DatabaseConnection.CreateTable<T>();
public List<T> GetItems()
lock (locker)
return DatabaseConnection.Table<T>().ToList();
public int GetItemsCount()
lock (locker)
return DatabaseConnection.Table<T>().Count();
public T GetItem(int id)
lock (locker)
return DatabaseConnection.Table<T>().Where(i => i.Id == id).FirstOrDefault();
public int SaveItem(T item)
lock (locker)
if (item.Id != 0)
return DatabaseConnection.Update(item);
else
return DatabaseConnection.Insert(item);
定义两个继承自 BaseModel 的示例类
public class Entity1 : BaseModel
public int ItemName
get;
set;
public class Entity2 : BaseModel
public int Description
get;
set;
public static UnityContainer Container get; private set;
public static void InitializeUnityContainer()
if (Container == null)
Container = new UnityContainer();
注册
Container.RegisterInstance<IBaseRepository<Entity1>>(new BaseRepository<Entity1>(DatabasePath));
Container.RegisterInstance<IBaseRepository<Entity2>>(new BaseRepository<Entity2>(DatabasePath));
这样解决
using (var repo1 = App.Container.Resolve<IBaseRepository<Entity2>>())
【讨论】:
以上是关于Xamarin 项目中 SQLite-Net 的通用存储库的主要内容,如果未能解决你的问题,请参考以下文章
SQLite-Net 扩展 - GetAllWithChildrenAsync 没有拉动一切
使用带有 sqlite-net orm 的 SQLiteConnection.Delete(object) 命令后更改 sqlite 文件大小