Generic Repository for SQLite-Net in Xamarin Project

不打扰是莪最后的温柔 提交于 2019-11-26 19:09:33

问题


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 Pro example have one Repository for the Task entity because that is the only entity it has.

In my own project I have more than one Entity, so my question is how can I make the following Customer Repository to become generic so that the ProductManager, EmployeeManager, etc can use it. If you know of an example or a blog post please point me to the right direction

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

回答1:


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



回答2:


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>>())
{

}


来源:https://stackoverflow.com/questions/29050400/generic-repository-for-sqlite-net-in-xamarin-project

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!