フロントエンドにWebフォームを使用し、管理コンソールにMVCを使用するソリューションがあります。
どちらのUIもNinjectを介してサービスレイヤーを使用しますが、微妙ではありますがかなり重要な問題を解決するのに問題があります。
文字列検索用語に基づいてコースのリストを返すCourseServiceがあるとします。このサービスは検索結果を返しますが、管理情報の目的で、行われた検索とその用語に一致するコースの数も記録する必要があります。
私は、リクエストの最後に、ボタンクリックイベントなどのページメソッドで、作業単位がUIによってコミットされるという考えから始めました。同じことがコントローラーにも当てはまります。
ここでの問題は、検索をログに記録するために、UI開発者が作業ユニットでCommit()を呼び出すことに依存していることです。UI開発者は、commitを呼び出さなくても問題なく続行でき、結果が返されますが、検索はログに記録されません。これは、サービス層に作業単位の範囲を制御させるという決定につながります。Ninjectは、作業単位をサービスレイヤーとリポジトリ実装の両方に自動的に渡します。これは、リクエストスコープごとに作成するようにninjectに指示したのと実質的に同じインスタンスになります。
これが私のレイヤーの書き方の例です...
public class CourseService
{
private readonly ICourseRepository _repo;
public CourseService(ICourseRepository repo)
{
_repo = repo;
}
public IEnumerable<Course> FindCoursesBy(string searchTerm)
{
var courses = _repo.FindBy(searchTerm);
var log = string.format("search for '{1}' returned {0} courses",courses.Count(),searchTerm);
_repo.LogCourseSearch(log);
//IMO the service layer should be calling Commit() on IUnitOfWork here...
return courses;
}
}
public class EFCourseRepository : ICourseRepository
{
private readonly ObjectContext _context;
public EFCourseRepository(IUnitOfWork unitOfWork)
{
_context = (ObjectContext)unitOfWork;
}
public IEnumerable<Course> FindBy(string text)
{
var qry = from c in _context.CreateObjectSet<tblCourse>()
where c.CourseName.Contains(text)
select new Course()
{
Id = c.CourseId,
Name = c.CourseName
};
return qry.AsEnumerable();
}
public Course Register(string courseName)
{
var c = new tblCourse()
{
CourseName = courseName;
};
_context.AddObject(c);
//the repository needs to call SaveChanges to get the primary key of the newly created entry in tblCourse...
var createdCourse = new Course()
{
Id = c.CourseId,
Name = c.CourseName;
};
return createdCourse;
}
}
public class EFUnitOfWork : ObjectContext, IUnitOfWork
{
public EFUnitOfWork(string connectionString) : base(connectionString)
{}
public void Commit()
{
SaveChanges();
}
public object Context
{
get { return this; }
}
}
上記のコメントでは、変更をコミットする必要があると感じる場所を確認できますが、サービスレイヤーとリポジトリ実装の両方でトランザクションのスコープを制御できるようにすることで、より大きな問題を見落としている可能性があります。
これに加えて、リポジトリが新しいオブジェクトを保存し、新しく指定された主キーをそのままにして返す必要がある場合、オブジェクトが返された後にUIからCommitを呼び出していると、これは発生しません。そのため、リポジトリは作業単位を管理する必要がある場合があります。
私のアプローチに差し迫った問題がありますか?