2015-03-14 21 views
14

Zastanawiam się, czy istnieje sposób na napisanie ogólnego repozytorium dla mojego projektu Xamarin, a nie na pisanie innego repozytorium dla każdej jednostki w moim obiekcie. Przykład Xamarin Tasky Pro ma jedno repozytorium dla encji Zadania, ponieważ jest to jedyna jednostka, którą ma.Generyczne repozytorium dla SQLite-Net w Xamarin Project

W moim własnym projekcie mam więcej niż jedną encję, więc moje pytanie brzmi: jak mogę uczynić następujące repozytorium klienta, aby stało się ogólne, aby ProductManager, EmployeeManager, itp. Mogli z niego korzystać. Jeśli znasz przykład lub wpis na blogu, proszę wskazać mi właściwy kierunek:

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

Teraz trzeba przejść w realizacji ISQlitePlatform w SQLiteConnectionWithLock i SQLiteConnection konstruktorów. Poprawna implementacja platformy jest automatycznie dodawana do projektu. –

Odpowiedz

40

To jest stare pytanie, ale oto moja implementacja.

Używam połączeń asynchronicznych, ponieważ zapewniają lepszą wydajność w projektach mobilnych. Nuggets, które zainstalowałem, to Sqlite.Net-PCL/SQLite.Net.Async-PCL w projekcie Core i odpowiadającym mu nuget w projekcie Android.

moim repozytorium wygląda następująco:

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

Niektóre przykłady, w jaki sposób z niego korzystać:

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

Jeśli repozytorium nie spełnia Twoich potrzeb zapytań, można użyć 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

Wow, świetnie. Właśnie tego szukam. Wykorzystam go i zobaczę, czy mogę go użyć do zastąpienia moich 7 różnych repozytoriów. –

+0

Właściciel ma zastrzeżony pakiet 'Sqlite.Net.Platform.XamarinAndroid'. Może to oznaczać, że pakiet jest przestarzały lub nie powinien już być używany. [LINK] (https://www.nuget.org/packages/SQLite.Net.Platform.XamarinAndroid/) –

+1

Jak to działa bez "Repozytorium klas publicznych : IRepository gdzie T: class, new()" – PEO

0

Moje wdrożenie przy pomocy jedności IOC jest podane poniżej, My pr oject zawiera PCL Xamarin Android & Xamarin iOS wystaje

określić model zasady z klucza głównego

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

zdefiniować ogólny repozytorium podstawy, jak pokazano poniżej

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


    } 

zdefiniować dwie klasy próbek, które są odziedziczone po BaseModelu

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

Rejestracja

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

jak rozwiązać ten

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

}