Repositoryパターン(aka DAOパターン)について
SomaではRepositoryパターンは必須というわけではないですが、推奨しています。
次のような抽象クラスを提供しています(メソッドとコンストラクタはシグネチャだけを表示)。
public abstract class RepositoryBase<TObjectContext, TEntity> where TObjectContext: ObjectContext where TEntity: EntityObject { // Fields private readonly Func<TObjectContext> _contextProvider; private readonly string _entitySetName; // Methods protected RepositoryBase(Func<TObjectContext> contextProvider); protected RepositoryBase(Func<TObjectContext> contextProvider, Func<Type, string> entitySetNameResolver); protected virtual TObjectContext GetObjectContext(); protected virtual TResult Execute<TResult>(Func<TObjectContext, TResult> contextHandler); protected virtual IList<TElement> ExecuteResourceQuery<TElement>(Expression<Func<string>> sqlKeyExpression, object param = null); protected virtual void IterateResourceQuery<TElement>(Action<TElement, IterationContext> callback, Expression<Func<string>> sqlKeyExpression, object param = null); protected virtual int ExecuteResourceCommand(Expression<Func<string>> sqlKeyExpression, object param = null); public virtual void Insert(TEntity entity); public virtual void Update(TEntity entity); public virtual void Delete(TEntity entity); }
このクラスを使うと、ObjectContextが隠蔽されるのでObjectContextに対してアプリがusingステートメントを使う必要がなくなります(RepositoryBaseがObjectContextの破棄を引き受けます)。usingステートメントは便利ですが、必ず使い忘れる人がいるので、抽象度の高いAPIには向いていないと思っています。
SQLファイルを実行できるのは、次のメソッドです。
- ExecuteResourceQuery
- 検索系SQLファイルを扱います。
- IterateResourceQuery
- 検索系SQLファイルを使ってエンティティを1件ずつ処理します。
- ExecuteResourceCommand
- 更新系SQLファイルを扱います。
LINQ to Entityは次のメソッドで扱います(わざわざこのメソッドを用意しているのはObjectContextを抽象クラス側でDisposeできるようにするため)。
- Execute
自動生成の更新系はEntity Frameworkにおまかせするpublicなメソッドを用意しています。
- Insert
- Update
- Delete
RepositoryBaseの利用例ですが、こんな感じになります。この例はEmployeeエンティティに対するRepositoryです。
internal class EmployeeRepository : RepositoryBase<SampleEntities, Employee> { public EmployeeRepository() : base(() => new SampleEntities("name=Soma.SampleEntities")) { } // LINQ to Entityで1件取得 public Employee SelectById(int id) { return Execute(context => context.Employee.Where(e => e.Id == id).Single()); } // SQLファイルを指定して取得 public Employee SelectByName(string name) { return ExecuteResourceQuery<Employee>(() => EmployeeResources.SelectByName, new {name}).First(); } // SQLファイルを指定して実行し、1件ごとに指定されたcallbackを呼び出す public void Iterate(Action<Employee, IterationContext> callback) { IterateResourceQuery(callback, () => EmployeeResources.SelectAll); } }