2015-03-14 17 views
14

Ich frage mich, ob es eine Möglichkeit gibt, ein generisches Repository für mein Xamarin-Projekt zu schreiben, anstatt ein anderes Repository für jede Entität in meinem Objekt zu schreiben. Das Beispiel Xamarin Tasky Pro verfügt über ein Repository für die Entität Task, da dies die einzige Entität ist, die es besitzt.Generisches Repository für SQLite-Net in Xamarin Projekt

In meinem eigenen Projekt habe ich mehr als eine Entität, also meine Frage ist, wie kann ich das folgende Kundenrepository machen, um generisch zu werden, damit der ProductManager, EmployeeManager, usw. es verwenden kann. Wenn Sie ein Beispiel kennen oder eine Blog-Post mich bitte auf die richtige Richtung

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

Sie jetzt in einer Implementierung von ISQlitePlatform in dem SQLiteConnectionWithLock und SQLiteConnection Bauer passieren müssen. Die korrekte Plattformimplementierung wird automatisch zum Projekt hinzugefügt. –

Antwort

40

Dies ist eine alte Frage, aber hier ist meine Umsetzung.

Ich verwende asynchrone Verbindungen, da sie eine bessere Leistung in mobilen Projekten bieten. Die Nuggets, die ich installiert habe, sind Sqlite.Net-PCL/SQLite.Net.Async-PCL auf dem Core-Projekt und dem entsprechenden nugget auf dem Android-Projekt.

Mein Repository sieht wie folgt aus:

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

Einige Beispiele, wie man es benutzt:

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

Wenn das Repository nicht erfüllt Ihre Anfrage Bedürfnisse, können Sie 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, großartig. Genau danach suche ich. Ich werde es verwenden und sehen, ob ich es verwenden kann, um meine 7 verschiedenen Repositories zu ersetzen –

+0

Der Besitzer hat 'Sqlite.Net.Platform.XamarinAndroid' Paket nicht aufgeführt. Dies könnte bedeuten, dass das Paket veraltet ist oder nicht mehr verwendet werden sollte. [LINK] (https://www.nuget.org/packages/SQLite.Net.Platform.XamarinAndroid/) –

+1

Wie funktioniert das ohne die "öffentliche Klasse Repository : IRepository wo T: Klasse, neue()" – PEO

0

Meine Implementierung mit Hilfe der Einheit IOC ist unten angegeben, Mein pr oject umfasst die PCL, Xamarin Android & Xamarin IOS vorspringt

Definieren eines Basismodells mit Primärschlüssel

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

ein generisches Basis Repository definieren, wie unten

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


    } 

zwei Musterklassen definieren, die geerbt vom 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)); 

Entschlossenheit wie dies

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

} 
Verwandte Themen