Generic Repository for SQLite-Net in Xamarin Project

后端 未结 2 878
梦如初夏
梦如初夏 2020-12-07 16:46

I am wondering if there is a way to write a generic repository for my Xamarin project versus writing a different Repository for each entity in my object. The Xamarin Tasky P

相关标签:
2条回答
  • 2020-12-07 17:35

    This is an old question but here is my implementation.

    I´m using async connections as they provide better performance in mobile projects. The nuggets I installed are Sqlite.Net-PCL/SQLite.Net.Async-PCL on the Core project and the corresponding nuget on the Android project.

    My Repository looks like this:

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

    Some examples on how to use it:

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

    If the Repository does not meet your query needs, you can use 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();
    }
    
    0 讨论(0)
  • 2020-12-07 17:36

    My implementation with the help of unity IOC is given below, My project includes the PCL, Xamarin Android & Xamarin iOS projects

    Define a base model with primary key

    public class BaseModel
    {
        [PrimaryKey, AutoIncrement]
        public int Id { get; set; }
    }
    

    Define a generic base repository as shown below

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

    Define two sample classes which are inherited from the 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();
        }
    

    Register

    Container.RegisterInstance<IBaseRepository<Entity1>>(new BaseRepository<Entity1>(DatabasePath));
        Container.RegisterInstance<IBaseRepository<Entity2>>(new BaseRepository<Entity2>(DatabasePath));
    

    resolve like this

    using (var repo1 = App.Container.Resolve<IBaseRepository<Entity2>>())
    {
    
    }
    
    0 讨论(0)
提交回复
热议问题