ローカル環境にDBが必要なアプリの場合、大抵はLiteDbを使ってきました。
今回は趣向を変えてEntityFrameworkCoreを使ってみようかなと思い、Repository Patternな感じで実装してみました。 AdapterはSQLiteを使います。
本エントリはその備忘録です。
作成したコードは以下にUpしてあります。
※ちなみにEntityFrameworkCore初挑戦です。
IRepository< T >
こんな感じのInterfaceを公開します。
public interface IRepository<T> where T : class, IEntity { IQueryable<T> Get (); IQueryable<T> Get (Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = ""); T GetById (Guid id); void Insert (T entity); void Update (T entity); void Delete (T entity); void SaveChange (); }
※filter, orderby, includeProperties
付きのI/FはこちらのBlogを参考にさせて頂きました。
GenericRepository< T >
IRepository< T >の実装です。
State
を書き換える処理は過剰かもしれませんね。
あと実際に使う場合はAsyncとかしないとダメだし_dbSet
は危険そうな臭いがしますね。
public class GenericRepository<T> : IRepository<T> where T : class, IEntity { private readonly TodoDbContext _context; DbSet<T> _dbSet; public GenericRepository (TodoDbContext context) { this._context = context; this._dbSet = _context.Set<T> (); } public void Delete (T entity) { if (_context.Entry (entity).State == EntityState.Detached) { _dbSet.Attach (entity); } _dbSet.Remove (entity); SaveChange (); } public IQueryable<T> Get () { return _dbSet; } public IQueryable<T> Get (Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "") { IQueryable<T> query = _dbSet; if (filter != null) { query = query.Where (filter); } foreach (var includeProperty in includeProperties.Split (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { query = query.Include (includeProperty); } if (orderBy != null) { return orderBy (query); } else { return query; } } public T GetById (Guid id) { return _dbSet.Find (id); } public void Insert (T entity) { _dbSet.Add (entity); SaveChange (); } public void SaveChange () { _context.SaveChanges (); } public void Update (T entity) { _dbSet.Attach (entity); var entry = _context.Entry (entity); entry.State = EntityState.Modified; SaveChange (); } }
SQLiteでInMemoryDatabase
全然知らなかったんですが、SQLiteにもInMemoryDatabaseあるんですね。
今回はSQLiteのInMemoryDatabseを使用してみます。
SQLiteのInMemoryDatabaseを使用する場合、connection.open()
しておく必要があるようです。
まぁ今回テストで動かすだけなので、DbContextのコンストラクタ内でOpenしちゃいます。
public class TodoDbContext : DbContext { public DbSet<Todo> TodoEntitys { get; set; } public DbSet<TodoTask> TodoDetailEntitys { get; set; } public TodoDbContext(DbContextOptions<TodoDbContext> options) : base(options) { // DBのAdapterによっては以下の処理は不要。詳細はTest1Async.csを参照 this.Database.OpenConnection(); this.Database.EnsureCreated(); } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); } }
実際に使う場合はこんな感じです。
var options = new DbContextOptionsBuilder<TodoDbContext>().UseSqlite("DataSource=testDB;mode=memory;cache=shared").Options; var context = new TodoDbContext(options); var repo = new TodoRepository(context); var entities = repo.Get();
おわり
どんな時にどんな内容のSQLを発行しているか分からないのが怖いですね。
ちゃんと使うなら、そこら辺の理解が必要な感じがします。個人プロジェクトにEntityFrameworkCoreはtoo muchって予感がする。
テーブル間でいっぱいリレーション張る予定もないので、LiteDbで十分すぎるんだよなー。とはいえせっかく自由に挑戦できる個人プロジェクトですし、EntityFramework使ってみようかな...。うーん。