visual studio pcl para net how ejemplo datos con bases c# xamarin repository-pattern sqlite-net

c# - studio - xamarin database sqlite



Repositorio genérico para SQLite-Net en el proyecto Xamarin (2)

Me pregunto si hay una manera de escribir un repositorio genérico para mi proyecto Xamarin versus escribir un Repositorio diferente para cada entidad en mi objeto. El ejemplo de Xamarin Tasky Pro tiene un Repositorio para la entidad Tarea porque esa es la única entidad que tiene.

En mi propio proyecto, tengo más de una entidad, por lo que mi pregunta es cómo puedo hacer que el siguiente repositorio de clientes se vuelva genérico para que ProductManager, EmployeeManager, etc. pueda usarlo. Si conoce un ejemplo o una publicación en un blog, indíqueme la dirección correcta

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


Esta es una vieja pregunta, pero aquí está mi implementación.

Estoy usando conexiones asíncronas ya que proporcionan un mejor rendimiento en proyectos móviles. Los nuggets que instalé son Sqlite.Net-PCL / SQLite.Net.Async-PCL en el proyecto Core y el nuget correspondiente en el proyecto de Android.

Mi repositorio se ve así:

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

Algunos ejemplos sobre cómo usarlo:

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 el Repositorio no cumple con sus necesidades de consulta, puede usar 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(); }


Mi implementación con la ayuda de la unidad IOC se da a continuación. Mi proyecto incluye los proyectos PCL, Xamarin Android y Xamarin iOS.

Definir un modelo base con clave principal

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

Defina un repositorio base genérico como se muestra a continuación

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

Defina dos clases de muestra que se heredan del modelo 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(); }

Registro

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

resolver así

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