web-dev-qa-db-ja.com

XamarinプロジェクトのSQLite-Netの汎用リポジトリ

オブジェクトのエンティティごとに異なるリポジトリを作成するのではなく、Xamarinプロジェクトの汎用リポジトリを作成する方法があるかどうか疑問に思っています。 Xamarin Tasky Pro の例では、タスクエンティティが1つしかないため、タスクエンティティ用に1つのリポジトリがあります。

私のプロジェクトには複数のエンティティがあるので、次のカスタマーリポジトリを汎用にして、ProductManager、EmployeeManagerなどがそれを使用できるようにするにはどうすればよいですか。例やブログ投稿を知っている場合は、正しい方向を教えてください

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);
        }
    }
24
Val Okafor

これは古い質問ですが、これが私の実装です。

モバイルプロジェクトでパフォーマンスが向上するため、非同期接続を使用しています。インストールしたナゲットはSqlite.Net-PCL/SQLite.Net.Async-PCLはCoreプロジェクトに、対応するnugetはAndroidプロジェクトにあります。

私のリポジトリは次のようになります:

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

それを使用する方法のいくつかの例:

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

リポジトリがクエリのニーズを満たさない場合は、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();
}
53
xleon

Unityの助けを借りた私の実装IOCは以下のとおりです。私のプロジェクトにはPCL、Xamarin Android&Xamarin iOSプロジェクトが含まれています

主キーで基本モデルを定義する

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

以下に示すように、汎用ベースリポジトリを定義します。

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


    }

BaseModelから継承された2つのサンプルクラスを定義する

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

登録

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

このように解決する

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

}
0
Shyju M