web-dev-qa-db-fra.com

Référentiel générique pour SQLite-Net dans le projet Xamarin

Je me demande s'il existe un moyen d'écrire un référentiel générique pour mon projet Xamarin par opposition à l'écriture d'un référentiel différent pour chaque entité de mon objet. Les Xamarin Tasky Pro example ont un seul référentiel pour l'entité Task car il s'agit de la seule entité dont il dispose.

Dans mon propre projet, j'ai plusieurs entités et ma question est donc: comment puis-je transformer le référentiel client suivant en générique afin que ProductManager, EmployeeManager, etc. puisse l'utiliser. Si vous connaissez un exemple ou un article de blog, veuillez me diriger dans la bonne 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);
        }
    }
18
Val Okafor

C'est une vieille question mais voici ma mise en œuvre. 

J'utilise des connexions asynchrones car elles offrent de meilleures performances dans les projets mobiles. Les nuggets que j'ai installés sont Sqlite.Net-PCL/SQLite.Net.Async-PCL sur le projet Core et le nuget correspondant sur le projet Android.

Mon référentiel ressemble à ceci:

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

Quelques exemples d'utilisation:

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

Si le référentiel ne répond pas à vos besoins en matière de requête, vous pouvez utiliser 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();
}
45
xleon

Mon implémentation à l'aide de l'unité IOC est donnée ci-dessous. Mon projet comprend les projets PCL, Xamarin Android et iOS

Définir un modèle de base avec clé primaire

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

Définissez un référentiel de base générique comme indiqué ci-dessous

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


    }

Définir deux exemples de classes hérités du modèle de base

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

Registre

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

résoudre comme ça

using (var repo1 = App.Container.Resolve<IBaseRepository<Entity2>>())
{

}
0
Shyju M